Wrapping React
One of Reflex's most powerful features is the ability to wrap React components. This allows us to build on top of the powerful React ecosystem, but interface with it through Python.
Most of Reflex's base components are just wrappers around the great
Chakra UI library. Let's see how you can wrap your own component in three easy steps.
Step 1: Install the Library
If you want a cool component for your app but Reflex doesn't provide it, there's a good chance it's available as a React component. Search the web for an
npm package that provides the component you want.
In this example, we will wrap the
react-colorful color picker component.
Step 2: Wrap the Library
To wrap the component, create a subclass of rx.Component
.
class ColorPicker(rx.Component):
library = "react-colorful"
tag = "HexColorPicker"
The two most important props are library
, which is the name of the npm package, and tag
, which is the name of the React component.
Reflex will automatically install the library
specified in your code if needed.
If your component depends on non-react JS libs to work, add them as a list in lib_dependencies
and the dependencies will be installed automatically.
A component may also have many props. You can add props by declaring them as rx.Var
s in the class. In this example, we have just one prop, value
, which is the current color.
class ColorPicker(rx.Component):
library = "react-colorful"
tag = "HexColorPicker"
color: rx.Var[str]
Finally, we must specify any event triggers that the component takes. This component has a single trigger to specify when the color changes.
class ColorPicker(rx.Component):
library = "react-colorful"
tag = "HexColorPicker"
color: rx.Var[str]
def get_event_triggers(self) -> dict[str, Any]:
return {
**super().get_event_triggers(),
"on_change": lambda e0: [e0],
}
Step 3: Use the Component
Now we're ready to use the component! Every component has a create
method. Usually you'll want to store this for easy access.
color_picker = ColorPicker.create
Then you can use it like any other Reflex component.
class ColorPickerState(rx.State):
color: str = "#db114b"
def index():
return rx.box(
rx.vstack(
rx.heading(ColorPickerState.color),
color_picker(
on_change=ColorPickerState.set_color
),
),
background_color=ColorPickerState.color,
padding="5em",
border_radius="1em",
)
That's it! We hope over time the Reflex ecosystem will grow to include many useful components. Our goal is to bring the full power of web development to Python.
Aliases
If you are wrapping another components with the same tag as a
component in your project you can use aliases to
differentiate between them and avoid naming conflicts.
Lets check out the code below, in this case if we needed to wrap another color picker
library with the same tag we use an alias to avoid a conflict.
class AnotherColorPicker(rx.Component):
library = "some-other-colorpicker"
tag = "HexColorPicker"
color: rx.Var[str]
def get_event_triggers(self) -> dict[str, Any]:
return {
**super().get_event_triggers(),
"on_change": lambda e0: [e0],
}
@classmethod
def get_alias(cls) -> Optional[str]:
return "OtherHexColorPicker"
Local Components
Javascript files containing custom React components may be added to the assets
directory of a Reflex project and then wrapped in python code using a relative path for the library
attribute.
As an example, save the following code as ./assets/welcome.js
export function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Then in your Reflex app, create a Component
wrapper referencing the relative path and exported component name.
class Welcome(rx.Component):
library = "../public/welcome.js"
tag = "Welcome"
name: rx.Var[str]
welcome = Welcome.create
(Note that the contents of assets
are compiled to .web/public
so the wrapped component uses the ../public
prefix for library
because the page code is compiled to a sibling directory, .web/pages
)
The local wrapped component can now be used like any other Reflex component.
def index():
return rx.vstack(welcome(name="Reflex"))
Import Types
By default, the library and tag specified in the Component are used to generate
a javascript import where the tag name is treated as the default import from the
library module.
import HexColorPicker from "react-colorful"
Non-default
If the tag is not the default export from the module, then set is_default = False
in the component class definition to generate an import using the curly brace syntax.
import { HexColorPicker } from "react-colorful"
Client-side Only
For components that do not work properly during server-side rendering, use _get_custom_code
to emit a dynamic loader.
class ReactPlayerComponent(rx.Component):
library = "react-player"
tag = "ReactPlayer"
def _get_imports(self) -> Optional[imports.ImportDict]:
return {}
def _get_custom_code(self) -> Optional[str]:
return """
import dynamic from "next/dynamic";
const ReactPlayer = dynamic(() => import("react-player/lazy"), { ssr: false });
"""
The strategy of emitting custom code can be used to surpass any current
limitations of the Reflex component compiler.