✨ Announcing our seed funding led by Lux Capital! Read more about it on our blog
DocsBlogChangelog

Search documentation...

/

Star

12k+

[ Learn ]

[ Concepts ]

[ Reference ]

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.Vars 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.

#db114b

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.
← MemoizationAPI Routes →

Copyright © 2023 Pynecone, Inc.