Reflex Cloud - Fast, secure & scalable hosting. One command to deploy.

Full Guide

Let's walk step by step through how to wrap a React component in Reflex, using the color picker as our primary example. You can also see the full API reference.

#db114b

Find The Component

There are two ways to find a component to wrap:

  1. Write the component yourself locally.
  2. Find a well-maintained React library on npm that contains the component you need.

In both cases, the process of wrapping the component is the same except for the library field.

In this guide we are wrapping the HexColorPicker component from the react-colorful library.

Define the Component

The first step to wrapping any React component is to subclass rx.Component.

Set the Library and Tag

The library is just the name of the npm package, and the tag is the name of the React component from the package that you want to wrap. Some packages have multiple components, and you can wrap each one as a separate Reflex component.

You can generally find the library and tag by looking at the import statement in the React code.

In this case, the library is react-colorful and the tag is HexColorPicker.

When you create your component, Reflex will automatically install the library for you.

Local Components

You can also wrap components that you have written yourself. Local components should be stored in your assets directory. For example, you could define a basic Hello component like this:

Then specify the library as following (note: we use the public directory here instead of assets as this is the directory that is served by the web server):

Local Packages

If the component is part of a local package, available on Github, or downloadable via a web URL, it can also be wrapped in Reflex. Specify the path or URL after an @ following the package name.

Any local paths are relative to the .web folder, so you can use ../ prefix to reference the Reflex project root.

Some examples of valid specifiers for a package called @masenf/hello-react are:

  • GitHub: @masenf/hello-react@github:masenf/hello-react
  • URL: @masenf/hello-react@https://github.com/masenf/hello-react/archive/refs/heads/main.tar.gz
  • Local Archive: @masenf/hello-react@../hello-react.tgz
  • Local Directory: @masenf/hello-react@../hello-react

It is important that the package name matches the name in package.json so Reflex can generate the correct import statement in the generated javascript code.

These package specifiers can be used for library or lib_dependencies.

Counter

Total value: 0

Although more complicated, this approach is useful when the local components have additional dependencies or build steps required to prepare the component for use.

Some important notes regarding this approach:

  • The repo or archive must contain a package.json file.
  • prepare or build scripts will NOT be executed. The distribution archive, directory, or repo must already contain the built javascript files (this is common).

Import Types

Sometimes the component is a default export from the module (meaning it doesn't require curly braces in the import statement).

In these cases you must set is_default = True in your component class, as we did in the Spline example in the overview section:

Library Dependencies

By default Reflex will install the library you have specified in the library property. However, sometimes you may need to install other libraries to use a component. In this case you can use the lib_dependencies property to specify other libraries to install.

As seen in the Spline example in the overview section, we need to import the @splinetool/runtime library to use the Spline component. We can specify this in our component class like this:

In this example we are adding this dependency to pin its version. It would be automatically installed alongside the react-spline library when the component is created.

A useful time to add lib_dependencies is when we are wrapping a component and we want plugins or extensions for the library. A good example is the React component react-markdown with its extensions.

Versions

You can specify the version of the library you want to install by appending @ and the version number to the library name.

This is recommended to ensure that your app works consistently across different environments.

Dynamic Imports

Some libraries you may want to wrap may require dynamic imports. This is because they they may not be compatible with Server-Side Rendering (SSR).

To handle this in Reflex, subclass NoSSRComponent when defining your component.

Often times when you see an import something like this:

You can wrap it in Reflex like this, here we are wrapping the react-plotly.js library which requires dynamic imports:

It may not always be clear when a library requires dynamic imports. A few things to keep in mind are if the component is very client side heavy i.e. the view and structure depends on things that are fetched at run time, or if it uses window or document objects directly it will need to be wrapped as a NoSSRComponent.

Some examples are:

  1. Video and Audio Players
  2. Maps
  3. Drawing Canvas
  4. 3D Graphics
  5. QR Scanners
  6. Reactflow

The reason for this is that it does not make sense for your server to render these components as the server does not have access to your camera, it cannot draw on your canvas or render a video from a file.

In addition, if in the component documentation it mentions nextJS compatibility or server side rendering compatibility, it is a good sign that it requires dynamic imports.

Additional Imports

Sometimes you may need to import additional files or stylesheets to use a component. You can do this by overriding the add_imports method in your component class. The method returns a dictionary where the key is the library and the values are a list of imports.

You can use the empty string as the key to import files that are not part of a library.

Aliases

If you are wrapping another component 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.

Custom Code

Sometimes you may need to add custom code to your component, such as definining constants and functions used. Custom code will be inserted outside of the react component function.

To add custom code to your component you can use the add_custom_code method in your component class.

Props

Props are the variables that you can pass to the component. In the case of our color picker, we have a single prop color. Props are defined using rx.Var with the type of the prop. Specifying the type helps the compiler catch errors and provides better intellisense.

Then when you create the component, you can pass in the props as keyword arguments.

Default Value

You can set a default value for the prop by assigning it in the class definition.

Serializers

Vars can be any type that can be serialized to JSON. This includes primitive types like strings, numbers, and booleans, as well as more complex types like lists, dictionaries, and dataframes.

In case you need to serialize a more complex type, you can use the serializer decorator to convert the type to a primitive type that can be stored in the state. Just define a method that takes the complex type as an argument and returns a primitive type. We use type annotations to determine the type that you want to serialize.

For example, the Plotly component serializes a plotly figure into a JSON string that can be stored in the state.

We can then define a var of this type as a prop in our component.

Event Handlers

Recall that event handlers are ways that components can handle user interactions. In the case of the color picker, we have a single event trigger on_change that triggers when the color changes. The event trigger takes a single argument color which is the new color.

We can then bind this event trigger to an event handler in our state that takes the color as an argument.

Assets

Experimental feature added in v0.5.3.

If a wrapped component depends on assets such as images, scripts, or stylesheets, these can kept adjacent to the component code and included in the final build using the rx._x.asset function.

rx._x.asset returns a relative path that references the asset in the compiled output. The target files are copied into a subdirectory of assets/external based on the module where they are initially used. This allows third-party components to have external assets with the same name without conflicting with each other.

For example, if there is an SVG file named wave.svg in the same directory as this component, it can be rendered using rx.image and rx._x.asset.

Debugging

If you encounter an error while wrapping a component it is recommended to check the Console in the browser developer tools. You can access this by going to inspect element and then clicking on the Console tab on Mac. This is because the Console is where most Javascript errors are logged.