# Reflex Documentation Source: http://localhost:3000/docs/ This file stitches together the full Reflex documentation as Markdown for AI agents and LLM indexing. For a navigable index with links to individual docs pages, see [llms.txt](http://localhost:3000/docs/llms.txt). # Project Structure (Advanced) Source: http://localhost:3000/docs/advanced-onboarding/code-structure.md ## App Module Reflex imports the main app module based on the `app_name` from the config, which **must define a module-level global named `app` as an instance of `rx.App`**. The main app module is responsible for importing all other modules that make up the app and defining `app = rx.App()`. **All other modules containing pages, state, and models MUST be imported by the main app module or package** for Reflex to include them in the compiled output. # Breaking the App into Smaller Pieces As applications scale, effective organization is crucial. This is achieved by breaking the application down into smaller, manageable modules and organizing them into logical packages that avoid circular dependencies. In the following documentation there will be an app with an `app_name` of `example_big_app`. The main module would be `example_big_app/example_big_app.py`. In the [Putting it all together](#putting-it-all-together) section there is a visual of the project folder structure to help follow along with the examples below. ### Pages Package: `example_big_app/pages` All complex apps will have multiple pages, so it is recommended to create `example_big_app/pages` as a package. 1. This package should contain one module per page in the app. 2. If a particular page depends on the state, the substate should be defined in the same module as the page. 3. The page-returning function should be decorated with `rx.page()` to have it added as a route in the app. ```python import reflex as rx from ..state import AuthState class LoginState(AuthState): @rx.event def handle_submit(self, form_data): self.logged_in = authenticate(form_data["username"], form_data["password"]) def login_field(name: str, **input_props): return rx.hstack( rx.text(name.capitalize()), rx.input(name=name, **input_props), width="100%", justify="between", ) @rx.page(route="/login") def login(): return rx.card( rx.form( rx.vstack( login_field("username"), login_field("password", type="password"), rx.button("Login"), width="100%", justify="center", ), on_submit=LoginState.handle_submit, ), ) ``` ### Templating: `example_big_app/template.py` Most applications maintain a consistent layout and structure across pages. Defining this common structure in a separate module facilitates easy sharing and reuse when constructing individual pages. **Best Practices** 1. Factor out common frontend UI elements into a function that returns a component. 2. If a function accepts a function that returns a component, it can be used as a decorator as seen below. ```python from typing import Callable import reflex as rx from .components.menu import menu from .components.navbar import navbar def template(page: Callable[[], rx.Component]) -> rx.Component: return rx.vstack( navbar(), rx.hstack( menu(), rx.container(page()), ), width="100%", ) ``` The `@template` decorator should appear below the `@rx.page` decorator and above the page-returning function. See the [Posts Page](#a-post-page-example_big_apppagespostspy) code for an example. ## State Management Most pages will use State in some capacity. You should avoid adding vars to a shared state that will only be used in a single page. Instead, define a new subclass of `rx.State` and keep it in the same module as the page. ### Accessing other States As of Reflex 0.4.3, any event handler can get access to an instance of any other substate via the `get_state` API. From a practical perspective, this means that state can be split up into smaller pieces without requiring a complex inheritance hierarchy to share access to other states. In previous releases, if an app wanted to store settings in `SettingsState` with a page or component for modifying them, any other state with an event handler that needed to access those settings would have to inherit from `SettingsState`, even if the other state was mostly orthogonal. The other state would also now always have to load the settings, even for event handlers that didn't need to access them. A better strategy is to load the desired state on demand from only the event handler which needs access to the substate. ### A Settings Component: `example_big_app/components/settings.py` ```python import reflex as rx class SettingsState(rx.State): refresh_interval: int = 15 auto_update: bool = True prefer_plain_text: bool = True posts_per_page: int = 20 def settings_dialog(): return rx.dialog(...) ``` ### A Post Page: `example_big_app/pages/posts.py` This page loads the `SettingsState` to determine how many posts to display per page and how often to refresh. ```python import reflex as rx from ..models import Post from ..template import template from ..components.settings import SettingsState class PostsState(rx.State): refresh_tick: int page: int posts: list[Post] @rx.event async def on_load(self): settings = await self.get_state(SettingsState) if settings.auto_update: self.refresh_tick = settings.refresh_interval * 1000 else: self.refresh_tick = 0 @rx.event async def tick(self, _): settings = await self.get_state(SettingsState) with rx.session() as session: q = ( Post .select() .offset(self.page * settings.posts_per_page) .limit(settings.posts_per_page) ) self.posts = q.all() @rx.event def go_to_previous(self): if self.page > 0: self.page = self.page - 1 @rx.event def go_to_next(self): if self.posts: self.page = self.page + 1 @rx.page(route="/posts", on_load=PostsState.on_load) @template def posts(): return rx.vstack( rx.foreach(PostsState.posts, post_view), rx.hstack( rx.button("< Prev", on_click=PostsState.go_to_previous), rx.button("Next >", on_click=PostsState.go_to_next), justify="between", ), rx.moment( interval=PostsState.refresh_tick, on_change=PostsState.tick, display="none" ), width="100%", ) ``` ### Common State: `example_big_app/state.py` _Common_ states and substates that are shared by multiple pages or components should be implemented in a separate module to avoid circular imports. This module should not import other modules in the app. ## Component Reusability The primary mechanism for reusing components in Reflex is to define a function that returns the component, then simply call it where that functionality is needed. Component functions typically should not take any State classes as arguments, but prefer to import the needed state and access the vars on the class directly. ### Memoize Functions for Improved Performance In a large app, if a component has many subcomponents or is used in a large number of places, it can improve compile and runtime performance to memoize the function with the `@lru_cache` decorator. To memoize the `foo` component to avoid re-creating it many times simply add `@lru_cache` to the function definition, and the component will only be created once per unique set of arguments. ```python from functools import lru_cache import reflex as rx class State(rx.State): v: str = "foo" @lru_cache def foo(): return rx.text(State.v) def index(): return rx.flex( rx.button( "Change", on_click=State.set_v(rx.cond(State.v != "bar", "bar", "foo")) ), *[foo() for _ in range(100)], direction="row", wrap="wrap", ) ``` ### example_big_app/components This package contains reusable parts of the app, for example headers, footers, and menus. If a particular component requires state, the substate may be defined in the same module for locality. Any substate defined in a component module should only contain fields and event handlers pertaining to that individual component. ### External Components Reflex 0.4.3 introduced support for the [`reflex component` CLI commands](/docs/custom-components/overview), which makes it easy to bundle up common functionality to publish on PyPI as a standalone Python package that can be installed and used in any Reflex app. When wrapping npm components or other self-contained bits of functionality, it can be helpful to move this complexity outside the app itself for easier maintenance and reuse in other apps. ## Database Models: `example_big_app/models.py` It is recommended to implement all database models in a single file to make it easier to define relationships and understand the entire schema. However, if the schema is very large, it might make sense to have a `models` package with individual models defined in their own modules. At any rate, defining the models separately allows any page or component to import and use them without circular imports. ## Top-level Package: `example_big_app/__init__.py` This is a great place to import all state, models, and pages that should be part of the app. Typically, components and helpers do not need to imported, because they will be imported by pages that use them (or they would be unused). ```python from . import state, models from .pages import index, login, post, product, profile, schedule __all__ = [ "state", "models", "index", "login", "post", "product", "profile", "schedule", ] ``` If any pages are not imported here, they will not be compiled as part of the app. ## example_big_app/example_big_app.py This is the main app module. Since everything else is defined in other modules, this file becomes very simple. ```python import reflex as rx app = rx.App() ``` ## File Management There are two categories of non-code assets (media, fonts, stylesheets, documents) typically used in a Reflex app. ### assets The `assets` directory is used for **static** files that should be accessible relative to the root of the frontend (default port 3000). When an app is deployed in production mode, changes to the assets directory will NOT be available at runtime! When referencing an asset, always use a leading forward slash, so the asset can be resolved regardless of the page route where it may appear. ### uploaded_files If an app needs to make files available dynamically at runtime, it is recommended to set the target directory via `REFLEX_UPLOADED_FILES_DIR` environment variable (default `./uploaded_files`), write files relative to the path returned by `rx.get_upload_dir()`, and create working links via `rx.get_upload_url(relative_path)`. Uploaded files are served from the backend (default port 8000) via `/_upload/` ## Putting it all together Based on the previous discussion, the recommended project layout look like this. ```text example-big-app/ ├─ assets/ ├─ example_big_app/ │ ├─ components/ │ │ ├─ __init__.py │ │ ├─ auth.py │ │ ├─ footer.py │ │ ├─ menu.py │ │ ├─ navbar.py │ ├─ pages/ │ │ ├─ __init__.py │ │ ├─ index.py │ │ ├─ login.py │ │ ├─ posts.py │ │ ├─ product.py │ │ ├─ profile.py │ │ ├─ schedule.py │ ├─ __init__.py │ ├─ example_big_app.py │ ├─ models.py │ ├─ state.py │ ├─ template.py ├─ uploaded_files/ ├─ pyproject.toml ├─ rxconfig.py ``` ## Key Takeaways - Like any other Python project, **split up the app into modules and packages** to keep the codebase organized and manageable. - Using smaller modules and packages makes it easier to **reuse components and state** across the app without introducing circular dependencies. - Create **individual functions** to encapsulate units of functionality and **reuse them** where needed. # Configuration Source: http://localhost:3000/docs/advanced-onboarding/configuration.md Reflex apps can be configured using a configuration file, environment variables, and command line arguments. ## Configuration File Running `uv run reflex init` will create an `rxconfig.py` file in your root directory. You can pass keyword arguments to the `Config` class to configure your app. For example: ```python # rxconfig.py import reflex as rx config = rx.Config( app_name="my_app_name", # Connect to your own database. db_url="postgresql://user:password@localhost:5432/my_db", # Change the frontend port. frontend_port=3001, ) ``` See the [config reference](https://reflex.dev/docs/api-reference/config/) for all the parameters available. ## Environment Variables You can override the configuration file by setting environment variables. For example, to override the `frontend_port` setting, you can set the `FRONTEND_PORT` environment variable. ```bash FRONTEND_PORT=3001 uv run reflex run ``` ## Command Line Arguments Finally, you can override the configuration file and environment variables by passing command line arguments to `uv run reflex run`. ```bash uv run reflex run --frontend-port 3001 ``` See the [CLI reference](/docs/api-reference/cli) for all the arguments available. ## Customizable App Data Directory The `REFLEX_DIR` environment variable can be set, which allows users to set the location where Reflex writes helper tools like Bun and NodeJS. By default we use Platform specific directories: On windows, `C:/Users//AppData/Local/reflex` is used. On macOS, `~/Library/Application Support/reflex` is used. On linux, `~/.local/share/reflex` is used. # How Reflex Works Source: http://localhost:3000/docs/advanced-onboarding/how-reflex-works.md We'll use the following basic app that displays Github profile images as an example to explain the different parts of the architecture. ```python demo exec import requests import reflex as rx class GithubState(rx.State): url: str = "https://github.com/reflex-dev" profile_image: str = "https://avatars.githubusercontent.com/u/104714959" @rx.event def set_profile(self, username: str): if username == "": return try: github_data = requests.get( f"https://api.github.com/users/{username}" ).json() except: return self.url = github_data["url"] self.profile_image = github_data["avatar_url"] def index(): return rx.hstack( rx.link( rx.avatar(src=GithubState.profile_image), href=GithubState.url, ), rx.input( placeholder="Your Github username", on_blur=GithubState.set_profile, ), ) ``` ## The Reflex Architecture Full-stack web apps are made up of a frontend and a backend. The frontend is the user interface, and is served as a web page that runs on the user's browser. The backend handles the logic and state management (such as databases and APIs), and is run on a server. In traditional web development, these are usually two separate apps, and are often written in different frameworks or languages. For example, you may combine a Flask backend with a React frontend. With this approach, you have to maintain two separate apps and end up writing a lot of boilerplate code to connect the frontend and backend. We wanted to simplify this process in Reflex by defining both the frontend and backend in a single codebase, while using Python for everything. Developers should only worry about their app's logic and not about the low-level implementation details. ### TLDR Under the hood, Reflex apps compile down to a [React](https://react.dev) frontend app and a [FastAPI](https://github.com/tiangolo/fastapi) backend app. Only the UI is compiled to Javascript; all the app logic and state management stays in Python and is run on the server. Reflex uses [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) to send events from the frontend to the backend, and to send state updates from the backend to the frontend. The diagram below provides a detailed overview of how a Reflex app works. We'll go through each part in more detail in the following sections. ```python eval rx.el.a( rx.image(src="https://web.reflex-assets.dev/other/architecture.webp"), href="https://web.reflex-assets.dev/other/architecture.webp", target="_blank", ) ``` ```python eval rx.box(height="1em") ``` ## Frontend We wanted Reflex apps to look and feel like a traditional web app to the end user, while still being easy to build and maintain for the developer. To do this, we built on top of mature and popular web technologies. When you run `uv run reflex run`, Reflex compiles the frontend down to a single-page [Next.js](https://nextjs.org) app and serves it on a port (by default `3000`) that you can access in your browser. The frontend's job is to reflect the app's state, and send events to the backend when the user interacts with the UI. No actual logic is run on the frontend. ### Components Reflex frontends are built using components that can be composed together to create complex UIs. Instead of using a templating language that mixes HTML and Python, we just use Python functions to define the UI. ```python def index(): return rx.hstack( rx.link( rx.avatar(src=GithubState.profile_image), href=GithubState.url, ), rx.input( placeholder="Your Github username", on_blur=GithubState.set_profile, ), ) ``` In our example app, we have components such as `rx.hstack`, `rx.avatar`, and `rx.input`. These components can have different **props** that affect their appearance and functionality - for example the `rx.input` component has a `placeholder` prop to display the default text. We can make our components respond to user interactions with events such as `on_blur`, which we will discuss more below. Under the hood, these components compile down to React components. For example, the above code compiles down to the following React code: ```jsx ``` Many of our core components are based on [Radix](https://radix-ui.com/), a popular React component library. We also have many other components for graphing, datatables, and more. We chose React because it is a popular library with a huge ecosystem. Our goal isn't to recreate the web ecosystem, but to make it accessible to Python developers. This also lets our users bring their own components if we don't have a component they need. Users can [wrap their own React components](/docs/wrapping-react/overview) and then [publish them](/docs/custom-components/overview) for others to use. Over time we will build out our [third party component ecosystem](/docs/custom-components/overview) so that users can easily find and use components that others have built. ### Styling We wanted to make sure Reflex apps look good out of the box, while still giving developers full control over the appearance of their app. We have a core [theming system](/docs/styling/theming) that lets you set high level styling options such as dark mode and accent color throughout your app to give it a unified look and feel. Beyond this, Reflex components can be styled using the full power of CSS. We leverage the [Emotion](https://emotion.sh/docs/introduction) library to allow "CSS-in-Python" styling, so you can pass any CSS prop as a keyword argument to a component. This includes [responsive props](/docs/styling/responsive) by passing a list of values. ## Backend Now let's look at how we added interactivity to our apps. In Reflex only the frontend compiles to Javascript and runs on the user's browser, while all the state and logic stays in Python and is run on the server. When you run `uv run reflex run`, we start a FastAPI server (by default on port `8000`) that the frontend connects to through a websocket. All the state and logic are defined within a `State` class. ```python class GithubState(rx.State): url: str = "https://github.com/reflex-dev" profile_image: str = "https://avatars.githubusercontent.com/u/104714959" def set_profile(self, username: str): if username == "": return github_data = requests.get(f"https://api.github.com/users/{username}").json() self.url = github_data["url"] self.profile_image = github_data["avatar_url"] ``` The state is made up of **vars** and **event handlers**. Vars are any values in your app that can change over time. They are defined as class attributes on your `State` class, and may be any Python type that can be serialized to JSON. In our example, `url` and `profile_image` are vars. Event handlers are methods in your `State` class that are called when the user interacts with the UI. They are the only way that we can modify the vars in Reflex, and can be called in response to user actions, such as clicking a button or typing in a text box. In our example, `set_profile` is an event handler that updates the `url` and `profile_image` vars. Since event handlers are run on the backend, you can use any Python library within them. In our example, we use the `requests` library to make an API call to Github to get the user's profile image. ## Event Processing Now we get into the interesting part - how we handle events and state updates. Normally when writing web apps, you have to write a lot of boilerplate code to connect the frontend and backend. With Reflex, you don't have to worry about that - we handle the communication between the frontend and backend for you. Developers just have to write their event handler logic, and when the vars are updated the UI is automatically updated. You can refer to the diagram above for a visual representation of the process. Let's walk through it with our Github profile image example. ### Event Triggers The user can interact with the UI in many ways, such as clicking a button, typing in a text box, or hovering over an element. In Reflex, we call these **event triggers**. ```python rx.input( placeholder="Your Github username", on_blur=GithubState.set_profile, ) ``` In our example we bind the `on_blur` event trigger to the `set_profile` event handler. This means that when the user types in the input field and then clicks away, the `set_profile` event handler is called. ### Event Queue On the frontend, we maintain an event queue of all pending events. An event consists of three major pieces of data: - **client token**: Each client (browser tab) has a unique token to identify it. This let's the backend know which state to update. - **event handler**: The event handler to run on the state. - **arguments**: The arguments to pass to the event handler. Let's assume I type my username "picklelo" into the input. In this example, our event would look something like this: ```json { "client_token": "abc123", "event_handler": "GithubState.set_profile", "arguments": ["picklelo"] } ``` On the frontend, we maintain an event queue of all pending events. When an event is triggered, it is added to the queue. We have a `processing` flag to make sure only one event is processed at a time. This ensures that the state is always consistent and there aren't any race conditions with two event handlers modifying the state at the same time. ```md alert info # There are exceptions to this, such as [background events](/docs/events/background-events) which allow you to run events in the background without blocking the UI. ``` Once the event is ready to be processed, it is sent to the backend through a WebSocket connection. ### State Manager Once the event is received, it is processed on the backend. Reflex uses a **state manager** which maintains a mapping between client tokens and their state. By default, the state manager is just an in-memory dictionary, but it can be extended to use a database or cache. In production we use Redis as our state manager. ### Event Handling Once we have the user's state, the next step is to run the event handler with the arguments. ```python def set_profile(self, username: str): if username == "": return github_data = requests.get(f"https://api.github.com/users/{username}").json() self.url = github_data["url"] self.profile_image = github_data["avatar_url"] ``` In our example, the `set_profile` event handler is run on the user's state. This makes an API call to Github to get the user's profile image, and then updates the state's `url` and `profile_image` vars. ### State Updates Every time an event handler returns (or [yields](/docs/events/yield-events)), we save the state in the state manager and send the **state updates** to the frontend to update the UI. To maintain performance as your state grows, internally Reflex keeps track of vars that were updated during the event handler (**dirty vars**). When the event handler is done processing, we find all the dirty vars and create a state update to send to the frontend. In our case, the state update may look something like this: ```json { "url": "https://github.com/picklelo", "profile_image": "https://avatars.githubusercontent.com/u/104714959" } ``` We store the new state in our state manager, and then send the state update to the frontend. The frontend then updates the UI to reflect the new state. In our example, the new Github profile image is displayed. # API Integration Source: http://localhost:3000/docs/ai/apis.md Not every service has a first-class integration — but your app can connect to **any external API** directly. By using standard HTTP requests, you can integrate with virtually any platform, fetch or send data, and trigger workflows without needing a prebuilt connector. This gives you full flexibility to work with modern REST, GraphQL, or other web APIs. ## What You Can Do With custom API calls, your app can: - Connect to **any REST or GraphQL API** on the web. - **Send and receive data** from external services. - Trigger actions like creating records, sending messages, or fetching analytics. - Build **custom automations** and workflows around APIs. - Chain API calls with other integrations or AI actions for powerful flows. ## Step 1: Get API Access 1. Identify the service you want to connect to. 2. Check its developer documentation for API access requirements. 3. Obtain the necessary credentials (e.g., **API key**, **token**, or **OAuth**). 4. Store credentials securely using environment variables — **never** hardcode secrets. *Example:* - **API Key:** `sk-xxxxxxxxxxxxxxxx` - **Base URL:** `https://api.example.com/v1/` ## Step 2: Hook up with your App 1. In the AI Builder navigate to the `secrets` tab and add your API credentials as secrets. 2. Then prompt the AI to use these secrets to do what you want and it will install the necessary libraries and set up the API calls for you. ## Step 3: Notes * **Keep secrets safe:** Use environment variables or secret storage for API keys. * **Check rate limits:** Many APIs have request limits — build accordingly. * **Combine with AI or other integrations:** For example, fetch data via API and summarize it using an LLM. With API integrations, you can connect your app to **almost any modern platform or service**, giving you unlimited extensibility beyond native integrations. # Copy App Source: http://localhost:3000/docs/ai/app-lifecycle/copy-app.md The **Copy** feature lets you duplicate an existing app inside Reflex Build. This is useful when you want to experiment with changes without affecting the original project, or when you want to use an app as a starting point for a new idea. ```python exec import reflex as rx def render_image(): return rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/app_lifecycle/copy_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ```python eval rx.el.div(render_image()) ``` ## How to Copy an App 1. In the Reflex Build workspace, click on the arrow down icon next to the deploy button and click on the **Copy** button. You can also do this in the Settings tab. 2. Reflex Build will create a new app in your workspace with the same: - Code files and components - State and configuration - Dependencies The copied app will appear as a separate project, independent from the original. ## Common Use Cases - **Experiment Safely** Try out new components, layouts, or integrations without risking your working app. - **Create Variations** Use the original app as a base to quickly spin up a different version (e.g., a light and dark theme version). - **Template Reuse** Turn an app into a personal template and copy it each time you start a new project. ## Best Practices - Rename your copied app immediately so it’s easy to distinguish from the original. # Deploy App Source: http://localhost:3000/docs/ai/app-lifecycle/deploy-app.md ```python exec import reflex as rx ``` It is easy to deploy your app into production from Reflex Build to Reflex Cloud. Simply click the `Deploy` button in the top right corner of Reflex Build, as shown below: ```python exec import reflex as rx def render_image(): return rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/app_lifecycle/deploy_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ```python eval rx.el.div(render_image()) ``` When deploying you can set the following options: - **App Name**: The name of your app - **Hostname**: Set your url by setting your hostname, i.e. if you set `myapp` as your hostname, your app will be available at `myapp.reflex.run` - **Region**: The regions where your app will be deployed - **VM Size**: The size of the VM where your app will be deployed - **Secrets**: The environment variables that will be set for your app, you can load the variables currently being used by your app by clicking the `Load from settings` button Note: Hostname customization, region selection, and VM sizing are only available on paid plans. # Download App Source: http://localhost:3000/docs/ai/app-lifecycle/download-app.md You can download your Reflex Build project if you want to work on it locally or self-host it outside the AI Builder. **Tip:** The recommended workflow is to use the GitHub integration, which keeps your code version-controlled and in sync. Downloading is useful if GitHub integration isn’t available or you just want a one-time export. ```python exec import reflex as rx def render_image(): return rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/app_lifecycle/download_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ```python eval rx.el.div(render_image()) ``` ## How to Download 1. In the AI Builder workspace, click on the arrow down icon next to the deploy button and click on the **Download** button. You can also do this in the Settings tab. 2. A `.zip` file will be generated containing your entire Reflex app, including: - Source code (`.py` files, components, state, etc.) - `requirements.txt` with dependencies - Config files (`rxconfig.py`, `.env`, etc.) # Fork App Source: http://localhost:3000/docs/ai/app-lifecycle/fork-app.md The **Fork App** feature lets you take an existing app and create your own version of it. This is perfect for **experimenting, customizing, or building on top of someone else’s work** without affecting the original app. ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/overview/fork_template_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## How to Fork an App 1. Browse or open an app you’d like to use as a starting point. 2. Click the **Fork** button in the app’s top right corner. 3. The AI Builder will create a **copy of the app** in your workspace. 4. You can now **edit, customize, and expand** your forked app independently of the original. ## What Happens When You Fork - You get a **full copy** of the original app, including all pages, components, and configurations. - The forked app is **completely separate**, so changes you make do not affect the original. - You can **rename, deploy, or share** your forked app like any other app in your workspace. ## Common Use Cases - **Start From an Example** Use a sample or shared app as a foundation to save time and learn best practices. - **Experiment Safely** Try new ideas or features without risking changes to the original app. - **Collaborate and Customize** Fork a teammate’s app to tailor it to your needs while keeping the original intact. # General App Settings Source: http://localhost:3000/docs/ai/app-lifecycle/general.md The **General App Settings** section lets you manage key aspects of your app, including its name, ID, and deletion. This is your central place to view and update your app’s core information. ```python exec import reflex as rx def render_image(): return rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/app_lifecycle/general_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ```python eval rx.el.div(render_image()) ``` ## How to Access Settings 1. In the AI Builder workspace, on the top bar click the more 3 dots icon and then click the **Settings** tab. 2. This will open the **Settings** tab to see your app’s main settings. ## What You Can Do - **Change App Name** Update the name of your app to reflect its purpose or version. - **Change App Visibility** Update the visibility of your app to public or private. - **View App ID** Find the unique identifier for your app, which can be used for integrations or support. - **Fork App** Fork your app to create a copy of it. -- **Download App** Download your app to your local machine. - **Delete App** Permanently remove an app you no longer need. **Warning:** This action cannot be undone. # Share App Source: http://localhost:3000/docs/ai/app-lifecycle/share-app.md The **Share** feature makes it easy to show your app to others without deploying it. When you share, Reflex Build generates a unique link that points to the current version of your project in the builder. ```python exec import reflex as rx def render_image(): return rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/app_lifecycle/share_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ```python eval rx.el.div(render_image()) ``` ## How to Share 1. In the AI Builder workspace, click on the arrow down icon next to the deploy button and click on the **Share** button. 2. A popup will appear with a **shareable link**. 3. Copy the link and send it to teammates, collaborators, or stakeholders. ## What Others See - The link opens a **read-only view** of your app generation. - Recipients can see the app preview but cannot make edits. - This makes it safe to share work-in-progress versions for quick feedback. ## Common Use Cases - **Get Feedback Quickly** Share a work-in-progress version with your team before deploying. - **Demo Features** Send a link to showcase a new component, layout, or integration. - **Collaboration** Share context with another developer before handing off to GitHub or download. # AI Testing Feature Source: http://localhost:3000/docs/ai/features/automated-testing.md ## Overview The Testing feature allows you to automatically test your generated applications for common issues and functionality problems. The AI will analyze your app and identify potential bugs, broken links, navigation issues, and other problems. ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src=rx.color_mode_cond( "https://web.reflex-assets.dev/ai_builder/features/test_light.webp", "https://web.reflex-assets.dev/ai_builder/features/test_dark.webp", ), class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## How to Use 1. **Start Testing**: Type "test this app" or similar command to activate testing mode 2. **AI Analysis**: The AI will automatically switch to testing mode and begin analyzing your application 3. **Review Results**: The preview tab switches to "Testing" mode to show the testing process and results ## What Gets Tested The AI automatically checks for: - **Broken Navigation**: Links that don't work or lead to missing pages - **Non-functional Buttons**: Buttons that don't respond or trigger errors - **Broken Links**: External or internal links that return errors - **UI/UX Issues**: Interface elements that don't function as expected - **Data Flow Problems**: Issues with forms, inputs, and data handling - **Layout Issues**: Visual or structural problems with the interface ## Testing Interface When testing is active: - The preview tab changes to "Testing" mode - You can see the AI interact with your application in real-time - Issues and results are reported as they're discovered - The testing process is visual and interactive ## Benefits - **Quality Assurance**: Catch issues before deployment - **Time Saving**: Automated testing is faster than manual checking - **Comprehensive Coverage**: Tests multiple aspects of your application # Connecting to Github Source: http://localhost:3000/docs/ai/features/connect-to-github.md --- tags: DevTools description: Integrate with GitHub to automate workflows and interact with your code repositories. --- ```python exec import reflex as rx ``` The Github integration is important to make sure that you don't lose your progress. It also allows you to revert to previous versions of your app. ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/connecting_to_github.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), ) ``` The GitHub integration allows you to: - Save your app progress - Work on your code locally and push your local changes back to Reflex.Build ## Github Commit History The commit history is a great way to see the changes that you have made to your app. You can also revert to previous versions of your app from here. ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/github_commit_history.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), ) ``` # App Style Customization Source: http://localhost:3000/docs/ai/features/customization.md ## Overview The App Style feature allows you to customize the visual appearance of your AI-generated applications. You can choose from predefined design themes or create custom styling to match your brand and preferences. ## How to Use 1. **Access the Feature**: Click on the App Style option to open the customization panel 2. **Choose Your Approach**: - **Custom**: Manually configure individual design elements - **Themes**: Select from professionally designed templates ## Custom Styling Options ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src=rx.color_mode_cond( "https://web.reflex-assets.dev/ai_builder/features/style_light.webp", "https://web.reflex-assets.dev/ai_builder/features/style_dark.webp", ), class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` When using Custom mode, you can adjust: - **Primary Color**: Choose your main brand color from 20+ preset options - **Secondary Color**: Select a complementary color for accents - **Typography**: Pick a font family for your app - **Border Radius**: Control how rounded corners appear - **Shadows**: Add depth with shadow effects - **Spacing**: Adjust the spacing between elements ## Themes These options are predefined popular themes you can choose for your app. Below are some of the available themes you can choose from ```python eval rx.el.div( rx.image( src=rx.color_mode_cond( "https://web.reflex-assets.dev/ai_builder/features/theme_light.webp", "https://web.reflex-assets.dev/ai_builder/features/theme_dark.webp", ), class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` - **Minimal Design**: Clean, geometric design with no shadows or gradients - **Modern UI**: Sleek, contemporary interface optimized for performance - **Carbon Design**: Enterprise-grade design following IBM's Carbon system - **Material Design**: Google's design language with elevation and semantic colors # Editor Modes Source: http://localhost:3000/docs/ai/features/editor-modes.md The AI Builder includes a powerful dual-mode editor that lets you view and edit your application code while tracking changes made by the AI. You can seamlessly switch between **Editor Mode** for manual code editing and **Diff Mode** for reviewing AI-generated changes. ```python exec import reflex as rx def render_image(): return rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/features/diff_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ```python eval rx.el.div(render_image()) ``` ## Modes: Editor vs Diff ### Editor Mode The standard code editor where you can: - **Write and modify code** directly in the interface - **Navigate through files** using the file tree - **Make manual changes** to your application - **Save your modifications** which persist across sessions ### Diff Mode A specialized view that highlights changes from the last AI prompt: - **Green highlights** show code additions made by the AI - **Red highlights** show code deletions made by the AI - **Side-by-side comparison** of what changed - **Line-by-line tracking** of modifications ## Switching Between Modes ### Toggle Controls Located in the editor toolbar, you'll find: - **Editor** button - Switch to normal editing mode - **Diff** button - Switch to change tracking mode ### When to Use Each Mode - **Use Editor Mode when:** - Making manual code changes - Writing new functionality - Debugging or fixing issues - General code development - **Use Diff Mode when:** - Reviewing what the AI changed after a prompt - Understanding modifications before accepting them - Tracking the impact of AI suggestions - Learning from AI-generated code patterns ## Understanding Diff Visualizations ### Code Highlighting **Additions (Green):** - New code lines added by the AI - New functions, components, or logic - Enhanced features and improvements **Deletions (Red):** - Code removed by the AI - Replaced or refactored sections - Deprecated functionality ### File Tree Indicators The file tree shows change statistics for each modified file: **Change Indicators:** - **`+5`** - 5 lines added to this file - **`-3`** - 3 lines removed from this file - **`+12 -8`** - 12 lines added, 8 lines removed - **No indicator** - File unchanged **Visual Cues:** - **Green `+` symbol** indicates files with additions - **Red `-` symbol** indicates files with deletions # File Tree Source: http://localhost:3000/docs/ai/features/file-tree.md The **File Tree** in Reflex Build lets you **view, organize, and manage all files and folders** in your project directly from the browser. It’s your central hub for navigating your app’s structure. ## Key Features ### Creating Folders - Click the **New Folder** button to create a folder inside the currently selected directory. - Enter a name and press **Enter** to confirm. - Folders can be nested to organize your project hierarchically. ### Creating Files - Click the **New File** button to create a file inside the current folder. - Enter a file name and extension (e.g., `main.py`) and press **Enter**. - Files are immediately visible in the tree and ready for editing in the code editor. ### Renaming Files or Folders - Right-click on a file or folder and select **Rename**. - Type the new name and press **Enter** to confirm. - Renaming automatically updates references in your project where applicable. ### Deleting Files or Folders - Right-click on a file or folder and select **Delete**. - Deleted items are permanently removed, so be careful when deleting important files. ### Drag-and-Drop from System - Drag files or folders from your computer directly into the File Tree. - The editor will automatically import them into the selected folder. - This works for individual files or entire folder structures, making adding assets or scripts quick and easy. # Reflex Build IDE Source: http://localhost:3000/docs/ai/features/ide.md Reflex Build includes a **powerful, in-browser IDE** built on **Monaco Editor**, designed to make coding fast, efficient, and enjoyable—all without leaving your browser. ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.video( src="https://www.youtube.com/embed/UAj9vUweQ5g", width="100%", height="400px", ), class_name="p-1 my-4 rounded-lg bg-slate-5", ) ``` ## Features ### Real-Time Editing Edit your code and see changes reflected immediately in your project. No manual saves or rebuilds—stay focused and iterate faster. ### Syntax Highlighting & Error Detection Write code confidently with **syntax highlighting**, **inline error alerts**, and **linting**. Catch issues as you type, reducing bugs and speeding up development. ### Code Snippets & Autocomplete Speed up development with **autocomplete** for functions, variables, and imports, as well as reusable **code snippets** for common patterns. ### Integrated Preview Quickly preview your changes directly in the editor without switching contexts, ensuring your app behaves as expected as you code. ### Built-In Terminal for Debugging Use the integrated terminal to run commands, debug issues, and inspect logs—all within the IDE. No need to switch tools or tabs. # Use Images as a prompt Source: http://localhost:3000/docs/ai/features/image-as-prompt.md ```python exec import reflex as rx ``` Uploading an image (screenshot) of a website (web) app of what you are looking to build gives the AI really good context. *This is the recommended way to start an app generation.* Below is an image showing how to upload an image to the AI Builder, you can click on the "Attach" button to upload an image, drag and drop an image, or paste an image from the clipboard: ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/image_upload.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` The advised prompt to use is: `Build an app from a reference image` # Installing External Packages Source: http://localhost:3000/docs/ai/features/installing-external-packages.md ```python exec import reflex as rx ``` Reflex Build allows you to install external python packages to use in your app. This is useful if you want to use a package that is not included in the default Reflex Build environment. Examples might include `openai`, `langsmith`, `requests`, etc. There are two ways to install external packages: 1. **Through the Chat Interface**: You can ask the AI to install a package for you. 2. **Add to the `requirements.txt` file**: You can add the package to the `requirements.txt` file and then save the app. This will install the package in your app's environment. ## Installing through the Chat Interface Enter the name of the package you want to install in the chat interface. The AI will then install the package for you. ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/external_packages_input.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## Installing through the requirements.txt file Add the package to the `requirements.txt` file and then save the app. This will install the package in your app's environment and recompile your app. ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/external_packages_requirements.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` # Integrations Shortcut Source: http://localhost:3000/docs/ai/features/integration-shortcut.md Reflex Build supports powerful integrations like databases, OpenAI, and Databricks, allowing you to connect external services to your app without complex setup. These integrations help you add advanced functionality—like AI-powered features, data analytics, or persistent storage—while speeding up development. The **Add Integrations** button makes it easy to connect external services to your app while chatting with the AI Builder. A panel with a list of available integrations will appear, you can quickly add integrations that your app can reference and connect to. Once in your app, you can access your integrations by clicking the flow or cog icon in the bottom left inside the chat area. ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src=rx.color_mode_cond( "https://web.reflex-assets.dev/ai_builder/features/shortcut_light.webp", "https://web.reflex-assets.dev/ai_builder/features/shortcut_dark.webp", ), class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## How to Use 1. In the AI Builder home, click the **Add Integrations** button. And if you're already in an app, click the flow or cog icon in the bottom left inside the chat area. 2. A list of available integrations will appear (e.g. Database, Databricks, OpenAI, etc.). 3. Click the Add button next to an integration to select it. 4. The integration will be added to your app and becomes available for connection. Then you can fill the required fields for the integration. 5. The AI Builder now knows your app has access to this integration and can generate code that uses it. ## What It Does - **Quick Access** – Easily browse and select from available integrations. - **Automatic Connection** – Integrations are added to your app and become available for the AI to use in generated code. - **No Manual Setup** – Skip complex configuration—the AI Builder handles the integration setup for you. ## Common Use Cases - **Database Queries** Show me the top 10 users ordered by signup date from my database. - **AI Features** Create a chat application that uses OpenAI to generate responses. # Knowledge Source: http://localhost:3000/docs/ai/features/knowledge.md The **Knowledge** feature lets you add context or rules that the AI Builder can reference when generating apps. This ensures your apps follow your guidelines, standards, or specific business logic. ```python exec import reflex as rx def render_image(): return rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/features/knowledge_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ```python eval rx.el.div(render_image()) ``` ## How to Add Knowledge 1. In the AI Builder top bar, click the more 3 dots icon and then click the **`Knowledge`** tab. 2. Enter your rule, guideline, or context description. 3. Save the entry. The AI Builder will automatically use it when generating apps. ## How It Works - The AI Builder references your knowledge entries as rules or guidelines. - Rules can define naming conventions, component usage, layout preferences, or other custom logic. - Multiple rules can be added to cover different aspects of app generation. ## Common Use Cases - **Maintain Consistency** Ensure all generated apps follow your company’s design or naming standards. - **Enforce Business Logic** Guide the AI Builder to follow specific workflows, validations, or feature requirements. - **Quickly Adapt AI Behavior** Add or update rules to influence new app generations without manual edits. # Restore Checkpoint Source: http://localhost:3000/docs/ai/features/restore-checkpoint.md The **Restore Checkpoint** feature allows you to roll back your app to any previous state during your AI Builder conversation. This is useful when you want to undo recent changes and return to an earlier version of your app. ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/features/restore_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## How It Works Every time the AI agent makes changes to your app, a checkpoint is automatically created. You can restore to any of these checkpoints at any time, effectively undoing all changes made after that point. ## Using Restore Checkpoint 1. **Locate the Restore Icon**: At the end of each AI agent message that made changes to your app, you'll see a circular arrow icon (↻). 2. **Click to Restore**: Click the circular arrow icon next to the message you want to restore to. 3. **Confirm the Action**: The app will restore to the exact state it was in after that specific message was processed. 4. **Continue Building**: After restoring, you can continue the conversation and make new changes from that point. ## When to Use Restore Checkpoint - **Undo Unwanted Changes**: When the AI made changes you don't like - **Try Different Approaches**: Restore and ask the AI to implement a feature differently - **Fix Broken Functionality**: Roll back when new changes break existing features - **Experiment Safely**: Test different solutions knowing you can always restore to a checkpoint ## Important Notes - Restoring will **permanently delete** all changes made after the selected message - You cannot undo a restore operation - choose your restore point carefully - The conversation history remains intact, but code changes after the restore point are lost - Restore checkpoint only affects your current building session > **Tip:** Before making major changes, note which message represents your last stable checkpoint so you can easily restore if needed. # Secrets Source: http://localhost:3000/docs/ai/features/secrets.md The **Secrets** feature allows you to securely store environment-specific values that your app can use, such as API keys, tokens, or other sensitive information. ```python exec import reflex as rx def render_image(): return rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/features/secrets_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ```python eval rx.el.div(render_image()) ``` ## Adding Secrets ### 1. Add Individually - **Description:** Set a single secret by providing a key and value. - **Example:** - Key: `OPENAI_API_KEY` - Value: `sk-xxxxxx` - **Behavior:** The secret is encrypted and accessible to your app at runtime. ### 2. Add in Bulk (Raw Editor) - **Description:** Upload multiple secrets at once using a simple `VAR=VALUE` format. - **Example:** ```text DATABASE_URL=postgresql://user:pass@host:5432/db STRIPE_SECRET_KEY=sk_test_xxxxx OPENAI_API_KEY=sk-xxxxxx ``` ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/features/secret_bulk_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` - **Behavior:** Each secret is securely stored and immediately available in the app environment. # Figma Source: http://localhost:3000/docs/ai/figma.md Integration Coming Soon! # Files Source: http://localhost:3000/docs/ai/files.md To upload a file to the AI Builder click the `📎 Attach` button and select the file you want to upload from your computer. You can also drag and drop files directly into the chat window. This section does not cover uploading images. Check out [Images](/docs/ai/images/) to learn more about uploading images. ```md alert ## Supported File Types The AI Builder currently supports the following file types for upload and processing: 1. `.pdf` 2. `.doc` 3. `.docx` 4. `.xls` 5. `.xlsx` 6. `.ppt` 7. `.pptx` 8. `.odt` 9. `.ods` 10. `.odp` 11. `.rtf` 12. `.csv` 13. `.txt` 14. `.md` 15. `.markdown` 16. `.json` 17. `.xml` 18. `.yaml` 19. `.yml` 20. `.tsv` ``` The files you upload will automatically be added to the `assets/` folder of your app, and the AI Builder will be able to read and process their contents as part of your prompts. The maximum number of files you can upload at a time is `5`. The maximum file size for uploads is `5MB`. If you need to work with larger files, consider breaking them into smaller chunks or using external storage solutions and linking to them via APIs. # Images Source: http://localhost:3000/docs/ai/images.md ## Upload an image as context for AI Builder To upload an image to the AI Builder that will be used as context for the AI builder to build an app that is similar to the image click the `📎 Attach` button and select the file you want to upload from your computer. You can also drag and drop files directly into the chat window. ```md alert ## Supported Image Types The AI Builder currently supports the following image types for upload and processing: 1. `.png` 2. `.jpg` 3. `.jpeg` 4. `.webp` 5. `.gif` 6. `.svg` 7. `.bmp` 8. `.tiff` 9. `.tif` 10. `.ico` ``` ## Upload an image to be used within the app If you want to upload an image to be used within the app, such as a company logo, then you can manually upload it to the `assets/` folder within the `code` tab. Drag and drop the image into the `assets/` folder. ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/add_images_to_assets.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` Video uploads are not currently supported but are coming soon! # AGENTS.md and CLAUDE.md Source: http://localhost:3000/docs/ai/integrations/agents-md.md `AGENTS.md` and `CLAUDE.md` are project-level instruction files that AI coding assistants read when they enter your repository. They give the assistant durable, repository-specific context so it follows Reflex conventions instead of generic defaults. - `AGENTS.md` is read by agents that follow the [AGENTS.md convention](https://agents.md), including Cursor, OpenCode, OpenAI Codex, and Pi. - `CLAUDE.md` is read by [Claude Code](https://code.claude.com/docs/en/memory). Claude Code does not read `AGENTS.md` directly — see [Sharing With Claude Code](#sharing-with-claude-code) below. A Reflex project should have at least one of these files at the project root, next to `rxconfig.py`. ## Recommended Content The [reflex-dev/agent-skills](https://github.com/reflex-dev/agent-skills) repository ships an `AGENTS.md` template that points assistants at the [Reflex Agent Skills](/docs/ai/integrations/skills/) for environment setup, documentation lookup, and process management. Use it as the starting point, then add anything specific to your codebase. ```md alert info # `AGENTS.md` references skills by name, so it works once the [Reflex Agent Skills](/docs/ai/integrations/skills/) are installed in the assistant. ``` ## Installation Download the template into your project root, next to `rxconfig.py`: ```bash curl -fsSL https://raw.githubusercontent.com/reflex-dev/agent-skills/main/AGENTS.md -o AGENTS.md ``` Or copy it manually from a local clone of the [reflex-dev/agent-skills](https://github.com/reflex-dev/agent-skills) repository. ## Sharing With Claude Code Claude Code reads `CLAUDE.md`, not `AGENTS.md`. To avoid duplicating content, create a `CLAUDE.md` that [imports](https://code.claude.com/docs/en/memory#import-additional-files) `AGENTS.md` using the `@` syntax: ```md @AGENTS.md ## Claude Code Add any Claude-specific instructions here. ``` Claude Code expands the `@AGENTS.md` import at session start, then appends anything you write below it. Both files stay in sync from a single source. After installation, your project root looks like: ```text my_app/ AGENTS.md CLAUDE.md rxconfig.py my_app/ my_app.py ``` ## Project-Specific Additions The template covers Reflex-wide setup. Below it, add anything else the assistant should know about your project: - Internal conventions and code style. - Required lint, type-check, or test commands. - Folder layout and where new code should go. - Hosting or deployment notes. Keep entries short and imperative — assistants follow concise, direct instructions more reliably than long paragraphs. ## Keeping Files Updated Reflex evolves quickly. If you used `curl` to download the template, re-run the same command to refresh it: ```bash curl -fsSL https://raw.githubusercontent.com/reflex-dev/agent-skills/main/AGENTS.md -o AGENTS.md ``` If you cloned the [reflex-dev/agent-skills](https://github.com/reflex-dev/agent-skills) repository, pull the latest changes and copy the file back into your project: ```bash cd agent-skills git pull cp AGENTS.md /path/to/your/reflex-project/AGENTS.md ``` ## Combining With Skills and MCP `AGENTS.md` and `CLAUDE.md` anchor the assistant in your project. Pair them with the other onboarding tools for deeper Reflex knowledge: - [Reflex Agent Skills](/docs/ai/integrations/skills/) provide reusable workflows that the file references by name. - [Reflex MCP](/docs/ai/integrations/mcp-overview/) provides structured documentation lookup at runtime. - The [llms.txt index](/llms.txt) gives a broad map of the documentation in one file. # AI Onboarding Source: http://localhost:3000/docs/ai/integrations/ai-onboarding.md ```python exec import reflex as rx def _resource_card( title: str, body: str, href: str, action: str, target: str = "_self" ) -> rx.Component: return rx.el.a( rx.el.div( rx.el.h3(title, class_name="text-base font-semibold text-secondary-12"), rx.el.p(body, class_name="text-sm leading-6 text-secondary-11"), rx.el.div(action, class_name="text-sm font-semibold text-primary-10"), class_name="flex h-full flex-col gap-2 rounded-lg border border-secondary-a4 bg-white-1 p-4 transition-colors hover:bg-secondary-2 shadow-xs", ), href=href, target=target, class_name="no-underline", ) def onboarding_resources() -> rx.Component: return rx.el.div( _resource_card( "Docs for Agents", "Give your agent current Reflex documentation as Markdown, llms.txt, or structured MCP context.", "/llms.txt", "Open llms.txt", target="_blank", ), _resource_card( "MCP", "Connect supported AI tools to Reflex documentation and component information through MCP.", "/ai/integrations/mcp-overview/", "View MCP overview", ), _resource_card( "Skills", "Install Reflex Agent Skills so assistants follow Reflex-specific workflows for docs, setup, and process management.", "/ai/integrations/skills/", "Install skills", ), _resource_card( "Reflex Build", "Use Reflex Build when you want an AI-native environment for creating, editing, previewing, and shipping apps.", "/ai/overview/best-practices/", "Read best practices", ), class_name="grid grid-cols-1 gap-3 md:grid-cols-2 my-6", ) ``` Everything you need to onboard your AI coding assistant to Reflex. If you are building Reflex apps with AI, combine current docs, structured MCP context, and local skills so the assistant can plan, code, run, and debug with the same assumptions as the Reflex docs. ```python eval onboarding_resources() ``` ## Prerequisite: Choose Your Workflow You do not need an API key to read Reflex documentation. Start by deciding how your assistant will work with Reflex: - For local app development, use Python 3.10 or newer and a project virtual environment. - For current documentation context, give the assistant Markdown docs or `llms.txt`. - For structured tool access, use the Reflex MCP integration. - For repeatable agent behavior, install Reflex Agent Skills. - For a browser-based AI builder, use Reflex Build. ## Reflex Docs for Agents You can give your assistant current Reflex documentation in a few ways. `````md tabs ## Markdown Pages Every docs page has a Markdown version that agents can read directly. Add `.md` to the docs path: ```text https://reflex.dev/docs/ai/integrations/ai-onboarding.md ``` Use this when an agent needs one focused page. ## llms.txt Use the generated docs index when an agent needs a broad map of Reflex docs: ```text https://reflex.dev/docs/llms.txt ``` The index groups docs by section and links to agent-friendly Markdown assets. ## MCP Use MCP when your editor or agent can call tools for structured documentation and component lookup: ```text https://build.reflex.dev/mcp ``` See the [MCP overview](/docs/ai/integrations/mcp-overview/) and [MCP installation](/docs/ai/integrations/mcp-installation/) guides for details. ````` ## Reflex MCP The Reflex MCP integration gives supported AI tools structured access to Reflex framework docs and component information. Use it when your assistant can connect to an MCP server and benefit from tool-assisted lookup while editing code. ```md alert warning # The Reflex MCP integration is currently only available for enterprise customers. Please [book a demo](https://reflex.dev/pricing/) to discuss access. ``` ## Reflex Agent Skills Reflex Agent Skills are local instruction packs that teach AI assistants how to work with Reflex projects. They cover: - Current Reflex docs and concept lookup. - Python environment setup for Reflex projects. - Reflex compile, run, restart, and debugging workflows. Install the skill pack from the [reflex-dev/agent-skills](https://github.com/reflex-dev/agent-skills) repository, or follow the [Skills installation guide](/docs/ai/integrations/skills/). ```bash npx skills add reflex-dev/agent-skills ``` ## Quick Start Prompts Use these prompts to give your agent a strong starting point. `````md tabs ## New App ```text Create a new Reflex app. Use current Reflex documentation, set up a Python 3.10+ virtual environment, initialize the project, and validate it with reflex compile --dry before handing it back. ``` ## Existing App ```text Work on this existing Reflex app. First inspect the project structure and current dependencies. Use Reflex docs for current APIs, make the requested change, then run reflex compile --dry or the project's existing test command. ``` ## Debugging ```text Debug this Reflex app. Read the error and relevant logs, identify whether the failure is in imports, state, event handlers, routing, components, or runtime setup, then apply the smallest fix and re-run validation. ``` ````` ## Reflex Build Reflex Build is the AI-native way to create Reflex apps in the browser. Use it when you want to generate, edit, preview, and share apps without setting up a local environment first. Start with the [Reflex Build best practices](/docs/ai/overview/best-practices/) guide, then use MCP and Skills when you want your local assistant to keep working with the same Reflex concepts. ## Recommended Validation Ask your assistant to validate Reflex changes before it hands work back: ```bash reflex compile --dry ``` For running apps, pair that with the process-management workflow from Reflex Agent Skills so the assistant restarts only the server process it owns. # Airtable Integration Source: http://localhost:3000/docs/ai/integrations/airtable.md --- tags: Data Infrastructure description: Connect your apps to Airtable to read, create, and update records in real time. --- The **Airtable Integration** lets your apps interact with Airtable bases to **store, fetch, and update structured data** directly from workflows, user actions, or automated triggers. Perfect for managing dynamic content, customer data, or workflows without complex backend setup. ## What You Can Do With the Airtable Integration, your app can: * Read and display data from Airtable bases * Create new records dynamically from user actions * Update or delete records through workflows * Power AI experiences with live database content * Sync structured data without hosting your own database ## Step 1: Get Your Airtable API Key 1. Go to [Airtable](https://airtable.com/). 2. Log in or create a free account. 3. Navigate to [**Developer Hub**](https://airtable.com/create/tokens) from your account menu. 4. Under **Personal access tokens**, click **Create token**. 5. Add the appropriate scopes (e.g. `data.records:read` and `data.records:write`). 6. Copy your API token. * Example: `patxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Click the **Settings** gear icon and navigate to the **Integrations** tab. 2. Find and enable the **Airtable** integration. 3. Paste your **API Key** in the input field. 4. Click **Connect** to confirm the connection. ## Step 3: Use in Your Workflows Once connected, you can use Airtable actions in your app to: * Fetch records to display dynamic lists * Add user submissions as new rows * Update status fields or metrics from AI workflows and more. # Anthropic Integration Source: http://localhost:3000/docs/ai/integrations/anthropic.md --- tags: AI description: Connect your apps to Anthropic's Claude models for advanced AI capabilities. --- The **Anthropic Integration** allows your app to use [Anthropic’s Claude models](https://www.anthropic.com/claude) for tasks such as text generation, summarization, reasoning, and other advanced AI capabilities. Once connected, you can call Claude directly from your workflows, UI actions, or automated triggers. ## Step 1: Obtain an Anthropic API Key 1. Go to the [Anthropic Console](https://console.anthropic.com/). 2. Navigate to **API Keys** in your account settings. 3. Click **Create Key** and give it a descriptive name (e.g., “AI Builder”). 4. Copy the generated key. * **Example:** `sk-ant-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Anthropic** in your app settings. 2. Paste your **Anthropic API Key** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can use Claude for AI-powered features across workflows and components. ## Step 3: Notes * **Keep your key secure:** Do not hardcode your Anthropic API key in public code repositories. * **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security. * **Secure API access:** The key allows your app to interact with Anthropic endpoints securely and efficiently. # AWS Integration Source: http://localhost:3000/docs/ai/integrations/aws.md --- tags: Data Infrastructure description: Connect to Amazon Web Services (AWS) for cloud storage, databases, compute, AI/ML, and more. --- The **AWS Integration** allows your app to connect to [Amazon Web Services (AWS)](https://aws.amazon.com/) — the world's most comprehensive cloud platform. Once connected, your app can access 200+ AWS services including storage, databases, compute, AI/ML, and more using the boto3 SDK. ## What You Can Do With AWS integration, your app can: - **S3 (Object Storage):** Upload, download, and manage files in S3 buckets. Generate presigned URLs for secure file access. Works with S3-compatible services like MinIO, Cloudflare R2, and DigitalOcean Spaces. - **DynamoDB (NoSQL Database):** Store and query data in a fully managed, serverless NoSQL database with single-digit millisecond performance. - **Lambda (Serverless Functions):** Invoke serverless functions, run code without managing servers, and build event-driven applications. - **SES (Email Service):** Send transactional emails, marketing emails, and notifications with high deliverability. - **SNS (Notifications):** Send push notifications, SMS, and email messages to users across multiple channels. - **SQS (Message Queues):** Build distributed, decoupled systems with reliable message queuing. - **Rekognition (Computer Vision):** Analyze images and videos for object detection, facial analysis, text extraction, and content moderation. - **Comprehend (NLP):** Extract insights from text using natural language processing for sentiment analysis, entity recognition, and topic modeling. - **Bedrock (AI Models):** Access foundation models from AI21 Labs, Anthropic, Cohere, Meta, Stability AI, and Amazon for generative AI applications. - **And 200+ more services:** EC2, RDS, CloudWatch, Polly, Textract, Translate, and many others. ## Step 1: Obtain AWS Credentials 1. Log in to the [AWS Console](https://console.aws.amazon.com/). 2. **Create IAM credentials:** - Navigate to **IAM (Identity and Access Management)**. - Click **Users** → **Add user** or select an existing user. - Attach policies based on the AWS services you plan to use: - **S3:** `AmazonS3FullAccess` or custom S3 policy - **DynamoDB:** `AmazonDynamoDBFullAccess` or custom DynamoDB policy - **Lambda:** `AWSLambdaFullAccess` or custom Lambda policy - **SES:** `AmazonSESFullAccess` or custom SES policy - **Multiple services:** Attach multiple policies or create a custom policy combining permissions **Example custom policy for S3 + DynamoDB:** ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:ListBucket", "dynamodb:PutItem", "dynamodb:GetItem", "dynamodb:Query", "dynamodb:Scan" ], "Resource": [ "arn:aws:s3:::YOUR_BUCKET_NAME/*", "arn:aws:dynamodb:YOUR_REGION:YOUR_ACCOUNT_ID:table/*" ] } ] } ``` 3. **Generate access keys:** - Under **Security credentials**, click **Create access key**. - Choose **Application running outside AWS** as the use case. - Copy your **Access Key ID** and **Secret Access Key**. **Example credentials:** * **Access Key ID:** `AKIAIOSFODNN7EXAMPLE` * **Secret Access Key:** `wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add AWS** in your app settings. 2. Enter your **AWS Access Key ID** and **AWS Secret Access Key**. 3. **(Optional)** Select your **AWS Region** (e.g., `us-east-1`, `eu-west-1`). Defaults to `us-east-1`. 4. **(Optional)** Enter an **AWS Endpoint URL** if using S3-compatible services: - **MinIO:** `http://localhost:9000` or your MinIO server URL - **Cloudflare R2:** `https://.r2.cloudflarestorage.com` - **DigitalOcean Spaces:** `https://.digitaloceanspaces.com` - Leave blank for standard AWS services. 5. Click **Connect** to validate and save your integration. Once connected, your app can access AWS services using boto3. ## Important Notes * **IAM permissions:** Ensure your IAM user has the necessary permissions for the AWS services you plan to use. Attach service-specific policies (e.g., `AmazonS3FullAccess`, `AmazonDynamoDBFullAccess`, `AWSLambdaFullAccess`) or create custom policies with least-privilege access. * **AWS Region:** Most AWS services are region-specific. Select the correct region where your resources are located (e.g., S3 buckets, DynamoDB tables, Lambda functions). * **Cost management:** Monitor AWS usage and costs through the AWS Billing Dashboard. Set up billing alerts to avoid unexpected charges. * **Security:** Rotate your access keys regularly and enable MFA for AWS console access. Apply least-privilege IAM policies to limit permissions to only what's needed. * **S3-compatible services:** For S3 operations, this integration works with S3-compatible storage like MinIO (self-hosted), Cloudflare R2 (zero egress fees), and DigitalOcean Spaces. Just provide the custom endpoint URL in the configuration. * **Service availability:** Not all AWS services are available in all regions. Check the [AWS Regional Services List](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) for service availability. # Azure Auth Manager Integration Source: http://localhost:3000/docs/ai/integrations/azure-auth.md --- tags: Authentication description: Integrate Azure for secure authentication and access management within your application. --- The **Azure Auth Manager Integration** allows your app to authenticate users through Microsoft Azure Active Directory (Azure AD). This integration provides secure OAuth 2.0 authentication and supports multi-tenant applications with customizable tenant access. ## Step 1: Set Up Azure App Registration Before connecting, you need to register your app in Azure Portal: 1 - Go to [Azure Portal](https://portal.azure.com) → **App Registrations** 2 - Click **New registration** as shown in the image below: ![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_1.webp) 3 - Register your app. Ensure that for the Redirect URI you select **Web** and enter the following URI that you find in the Azure Auth Manager integration settings in AI Builder: ``` https://{your-sandbox}/authorization-code/callback ``` ![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_2.webp) 4 - On the next page get your `client_id` (`AZURE_CLIENT_ID`) and `tenant_id` (`AZURE_VALID_TENANT_IDS`) from the **Overview** tab. ![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_3.webp) 5 - Next click `Add a certificate or secret` and copy the generated secret value (`AZURE_CLIENT_SECRET`). ![Azure App Registration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/azure_auth_4.webp) ## Step 2: Configure the Integration 1. Go to the **Integrations** section in your app settings by clicking **`@`** and then clicking the **Integrations** tab at the top. 2. Click **Add** next to Azure Auth Manager. 3. Fill in the credential fields: - Enter your Azure Client ID - Enter your Azure Client Secret - Enter valid tenant IDs (comma-separated for multiple tenants) 4. Click **Connect** to save the integration. Your app can now authenticate users through Azure AD with secure OAuth 2.0 flow. # Cartesia Integration Source: http://localhost:3000/docs/ai/integrations/cartesia.md --- tags: AI description: Add Cartesia’s powerful text-to-speech capabilities for realistic, real-time voice output and audio experiences. --- The **Cartesia Integration** allows your app to generate **high-quality, realistic speech from text** using Cartesia’s advanced voice models. Once connected, you can easily add real-time voice capabilities to workflows, user interactions, and automated experiences. ## Step 1: Obtain a Cartesia API Key 1. Go to the [Cartesia Console](https://www.cartesia.ai/). 2. Log in or create an account. 3. Navigate to **API Keys** in your account settings. 4. Click **New**, give it a descriptive name (e.g., “AI Builder”), and copy it. - Example: `sk_car_xxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Open your app and go to **Integrations → Add Cartesia**. 2. Paste your **Cartesia API Key** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can convert text to speech seamlessly in real time or through workflows. ## Step 3: Notes - **Secure API Access:** Keep your Cartesia API key safe. Do not hardcode it in public code. - **Environment isolation:** Use different keys for dev, staging, and production to ensure clean separation. - **Low latency:** Cartesia supports real-time streaming for conversational experiences. - **Usage management:** Monitor your Cartesia dashboard for quotas, billing, and usage insights. # Cohere Integration Source: http://localhost:3000/docs/ai/integrations/cohere.md --- tags: AI description: Add Cohere’s language models for text generation, classification, retrieval, embeddings, and more. --- The **Cohere Integration** allows your app to use [Cohere’s](https://cohere.com) state-of-the-art language models for natural language understanding and generation. Once connected, your app can power search, summarization, embeddings, classification, and conversational AI features directly from workflows and triggers. ## Step 1: Obtain a Cohere API Key 1. Go to the [Cohere Dashboard](https://dashboard.cohere.com/). 2. Log in or create an account. 3. Navigate to **API Keys** in your account settings. 4. Click **Create Key**, give it a descriptive name (e.g., “AI Builder”), and copy the key. ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Cohere** in your app settings. 2. Paste your **Cohere API Key** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can access Cohere’s endpoints for language tasks like embeddings, classification, chat, and more. ## Step 3: Notes - **Secure API Access:** Keep your Cohere API key private — do not hardcode it in public repositories. - **Environment separation:** Use different keys for development, staging, and production environments. - **Performance:** Cohere’s models support fast inference for production-ready experiences. - **Observability:** Use the Cohere dashboard to monitor usage, quotas, and request logs. # Database Integration Source: http://localhost:3000/docs/ai/integrations/database.md --- tags: Data Infrastructure description: Connect to SQL or NoSQL databases to query, store, and manage structured data. --- The Database Integration allows you to connect your AI-generated applications to real databases, automatically generating schemas and enabling data-driven functionality. ## Supported Databases - **PostgreSQL** - Recommended for production applications - **MySQL** - Popular open-source database - **SQLite** - Lightweight database, perfect for development and small applications - **MSSQL** - Microsoft SQL Server support ## Getting Started ### Opening the Database Integration 1. Navigate to your app in the AI Builder 2. Open the **Settings drawer** (gear icon) 3. Click on the **Integrations** tab 4. Find and enable the **Database** integration ### Connection Methods The Database Integration offers two convenient ways to connect: #### 1. Connection Details (Recommended) This user-friendly form breaks down your database connection into individual fields: **For PostgreSQL, MySQL and MSSQL:** - **Database Type**: Select from dropdown (PostgreSQL/MySQL/MSSQL) - **Hostname**: Your database server address (e.g., `localhost`, `db.company.com`) - **Port**: Automatically filled (PostgreSQL: 5432, MySQL: 3306, MSSQL: 1433) or specify custom port - **Username**: Your database username - **Password**: Your database password (securely handled) - **Database Name**: The specific database to connect to **For SQLite:** - **Database Type**: Select "SQLite" from dropdown - **SQLite Download URL**: Either a local file path or HTTP URL to download the database file #### 2. Database URI For advanced users who prefer the traditional connection string format: **PostgreSQL:** ``` postgresql://username:password@hostname:port/database_name ``` **MySQL:** ``` mysql://username:password@hostname:port/database_name ``` **MSSQL:** ``` mssql://username:password@hostname:port/database_name ``` **SQLite:** ``` sqlite:///path/to/database.sqlite sqlite+https://example.com/database.sqlite ``` ## Database URI Components Protocol (postgresql://) - Database type identifier Username (admin) - Database user credentials Password (secret123) - User password (kept secure) Hostname (db.company.com) - Server address Port (5432) - Connection port Database (mydatabase) - Target database name ## Connection Process 1. **Choose your method**: Use either Connection Details form or Database URI 2. **Fill in credentials**: Provide your database connection information 3. **Click Connect**: The system will validate and test your connection 4. **Schema Generation**: Upon successful connection, the system automatically: - Connects to your database - Analyzes the database structure - Generates SQLAlchemy models - Makes schema available to the AI for queries ```md alert # NoSQL Databases NoSQL databases (e.g., MongoDB, DynamoDB) can be accessed via Python SDKs which the AI Builder can install if you prompt for it. The first class Database integration currently supports only SQL databases. ``` # Databricks Integration Source: http://localhost:3000/docs/ai/integrations/databricks.md --- tags: Data Infrastructure description: Connect with Databricks to run data pipelines and advanced analytics seamlessly. --- The **Databricks Integration** allows your app to connect to [Databricks](https://www.databricks.com/) for secure data access, querying, and analytics. Once connected, you can run SQL queries, retrieve results, and power data-driven workflows directly from your app. ## What You Can Do With Databricks, your app can: - Connect securely to your Databricks workspace. - Run **SQL queries** or fetch data programmatically. - Build **dashboards and data visualizations** on top of your Databricks tables. - Automate workflows triggered by new or updated data. - Combine Databricks with AI models for advanced analytics. ## Step 1: Get Your Databricks Credentials ### 1 - Log in to your [Databricks Workspace](https://databricks.com/). ### 2 - Get your **DATABRICKS_HOST** and **DATABRICKS_WAREHOUSE_ID**: - Go to `SQL Warehouses` from the sidebar. - Select your desired warehouse. - Click `Connection details`. - Copy the Server hostname (this is your **DATABRICKS_HOST**). - Copy the HTTP path removing the `/sql/1.0/warehouses/` prefix (this is your **DATABRICKS_WAREHOUSE_ID**). ![databricks_integration_1.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_1.webp) ### 3 - Get your **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA**: - Click the SQL Editor from the sidebar. - Choose the **DATABRICKS_CATALOG** and **DATABRICKS_SCHEMA** from the dropdowns as shown below. ![databricks_integration_4.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_4.webp) ### 4 - Obtain your authentication credentials: There are two methods to authenticate your app with Databricks: using interactive U2M **OAuth** or via registered M2M **Service Principal**. Choose one of the methods below to obtain the necessary credentials. ---md tabs --tab OAuth with Databricks #### Interactive Login with your Databricks Account If your workspace administrator has already added Reflex as a Connected App in your Databricks workspace, you should see a "Login with Databricks" button after entering your DATABRICKS_HOST. -- --tab Service Principal #### M2M Service Principal (DATABRICKS_CLIENT_ID and DATABRICKS_CLIENT_SECRET) - Open the dropdown in the top right corner and select **Manage Account**. ![databricks_integration_oauth_1.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_1.webp) - Select `Users and Groups` ![databricks_integration_oauth_2.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_2.webp) - Select the `Service Principals` tab and click `Add Service Principal`. ![databricks_integration_oauth_3.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_3.webp) - Fill in the details and click `Add Service Principal`. ![databricks_integration_oauth_4.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_4.webp) - Click the `Credentials and Secrets` tab and click `Generate Secret`. ![databricks_integration_oauth_5.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_5.webp) - Set a lifetime for the secrets and click `Generate`. ![databricks_integration_oauth_6.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_6.webp) - Copy the generated **DATABRICKS_CLIENT_ID** and **DATABRICKS_CLIENT_SECRET**. ![databricks_integration_oauth_7.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_integration_oauth_7.webp) -- --- ## Step 2: Configure the Integration in Your App 1. In your app, go to **Integrations** and **Add Databricks**. 2. Paste your **DATABRICKS_HOST** 3. Select your authentication method: - OAuth, if configured. - Service Principal, provide the client ID and secret gathered previously. 2. Paste or select your 1. **DATABRICKS_WAREHOUSE_ID** 2. **DATABRICKS_CATALOG** 3. **DATABRICKS_SCHEMA** 3. Click **Connect** to validate and save your integration. Once connected, the AI Builder can execute queries directly against your Databricks environment. ## Step 3: Notes * **Secure your token:** Never expose tokens in public code. * **Permissions:** Ensure your token or service account has the required workspace and table permissions. * **Combine with AI:** Use query outputs to power models, summaries, or alerts in real time. # How to Enable Login as an Admin - Login to Databricks - Go to manage account ![databricks_admin_auth_1.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_1.webp) - Go to **Settings** → **Apps Connections** → **Add new connection** ![databricks_admin_auth_2.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_2.webp) - Give it a name, enter the redirect URL that Reflex Build provides, Click `All APIs` and uncheck `Generate a client secret` and then add. - URL: `https://build.reflex.dev/_reflex_oidc_databricks/authorization-code/callback` ![databricks_admin_auth_3.webp](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/databricks_admin_auth_3.webp) # Descope Integration Source: http://localhost:3000/docs/ai/integrations/descope.md --- tags: Authentication description: Add Descope’s identity and authentication platform to your apps to manage user sign-in, onboarding, MFA, SSO, and flows with ease. --- The **Descope Integration** enables your app to leverage Descope’s full Customer Identity & Access Management (CIAM) features—visual authentication flows, identity management, SSO, MFA, tenant isolation, and more. Once set up, you can orchestrate secure user journeys across your application with minimal coding. ```md alert warning # You must open your app in a new tab from the builder to test the Descope integration. ``` ## What You Can Do With Descope Integration, your app can: - Handle user sign-up, login, and passwordless flows seamlessly - Enable multifactor authentication (MFA), passkeys, and social login - Support single sign-on (SSO) via OIDC/SAML - Manage users, roles, tenants, and permissions via management APIs - Orchestrate onboarding, branding, and multi-tenant flows via drag-and-drop workflows - Sync user data with tools like HubSpot or Segment via built-in connectors ## Step 1: Obtain Descope Credentials ![Descope Credentials](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope.webp) 1. Log in to the [**Descope Console** (or sign up)](https://www.descope.com/sign-up). 2. Create your first Project. 3. Go to the Project page under Settings. 4. Copy the `Project ID`. ## Step 2: Configure the Integration in Your App 1. In your app’s settings or integration dashboard, select **Add Descope**. 2. Enter your **PROJECT_ID**. 3. (Optional) Pick a **DESCOPE_FLOW_ID** (e.g. “sign-up-or-login”) and **SESSION_SECRET_KEY** or press the Clipboard Copy to use default values. 4. Click **Connect** to validate credentials and enable Descope features. ![Descope Integration](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/descope_2.webp) # Gemini Integration Source: http://localhost:3000/docs/ai/integrations/gemini.md --- tags: AI description: Connect your apps to Google’s Gemini models for advanced AI capabilities. --- The **Gemini Integration** allows your app to use [Google’s Gemini models](https://aistudio.google.com/) for text generation, reasoning, multimodal analysis, and other advanced AI capabilities. Once connected, you can call Gemini directly from your workflows, UI actions, or automated triggers. ## Step 1: Obtain a Gemini API Key 1. Go to [Google AI Studio](https://aistudio.google.com/). 2. Navigate to **Get API Key** or create a new key for your project. 3. Copy the generated key. ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Gemini** in your app settings. 2. Paste your **Gemini API Key** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can use Gemini for AI-powered features across workflows and components. ## Step 3: Notes * **Keep your key secure:** Do not hardcode your Gemini API key in public code repositories. * **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security. * **Secure API access:** The key allows your app to interact with Gemini endpoints securely and efficiently. # GitHub Integration Source: http://localhost:3000/docs/ai/integrations/github.md --- tags: Developer Tools description: Connect your app to GitHub to automate workflows, manage repositories, and integrate developer operations. --- The **GitHub Integration** lets your app connect directly to [GitHub](https://github.com) to automate actions, fetch data, and build powerful developer workflows. Once connected, your app can interact with repositories, issues, pull requests, and more. ## What You Can Do With GitHub, your app can: - Fetch and display repository data (commits, branches, issues, etc.). - Create or update issues, pull requests, and discussions. - Trigger workflows or CI/CD pipelines. - Sync GitHub activity into your app’s dashboards or automations. - Build custom developer tools using GitHub’s API. ## Step 1: Generate a Personal Access Token 1. Go to your [GitHub Settings](https://github.com/settings/tokens). 2. Navigate to **Developer settings → Personal access tokens**. 3. Click **Generate new token** (classic or fine-grained). 4. Select the required scopes (e.g., `repo`, `workflow`, `read:user`). 5. Copy the token. **Example token:** ``` ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ``` (Note: Replace the above value with your actual GitHub token) > 💡 Fine-grained tokens are recommended for better security. ## Step 2: Configure the Integration in Your App 1. In your app, go to **Integrations → Add GitHub**. 2. Paste your **GitHub Personal Access Token** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can start interacting with GitHub through workflows and actions. ## Step 3: Notes * **Keep your token secure:** Never expose your GitHub token in public code. * **Use fine-grained permissions:** Limit access to only what’s needed. * **API rate limits:** GitHub imposes API limits, so plan automations accordingly. * **Combine with AI:** For example, auto-generate release notes from commits or summarize PRs with LLMs. # Google Auth Integration Source: http://localhost:3000/docs/ai/integrations/google-auth.md --- tags: Authentication description: Enable secure authentication using Google sign-in and OAuth 2.0 workflows. --- The **Google Auth Integration** allows your app to authenticate users using their Google accounts. This provides a secure, familiar login experience and simplifies user management. ## Step 1: Create a Google OAuth Client 1 - Go to the [Google Cloud Console](https://console.cloud.google.com/) 2 - Navigate to **APIs & Services → Credentials** 3 - Click **Create Credentials** ![Google Auth 1](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_1.webp) 4 - Choose **OAuth client ID**. ![Google Auth 2](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_2.webp) 5 - Choose **Web Application** as the application type, name the application and enter your sandbox URL, which you get from the Google Auth integration panel, as the **Authorized JavaScript Origin** and **Authorized Redirect URIs**. ![Google Auth 3](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_3.webp) 6 - Copy the generated **Client ID** (`GOOGLE_CLIENT_ID`) and **Client Secret** (`GOOGLE_CLIENT_SECRET`). ![Google Auth 4](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/google_auth_4.webp) ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Google Auth** in your app settings. 2. Enter your **Google Client ID** and **Google Client Secret**. 3. Save the integration. Your app is now configured to use Google Auth for login. ## Step 3: Notes - The integration supports multiple environments (development, staging, production). Use environment-specific secrets for the client ID and secret. - Google Auth handles token refresh automatically when users log in via OAuth. - Users will see a standard Google login screen, ensuring familiarity and trust. - Ensure your app domain matches the authorized JavaScript origin and redirect URIs; otherwise, authentication will fail. # Groq Integration Source: http://localhost:3000/docs/ai/integrations/groq.md --- tags: AI description: Connect your apps to Groq’s ultra-fast inference API for lightning-speed AI responses. --- The **Groq Integration** allows your app to use [Groq’s API](https://groq.com/) for ultra-fast AI inference. Once connected, your app can leverage Groq’s hosted models (including open models like Llama 4 and Qwen) to power real-time workflows, chat experiences, and other AI-driven features. ## Step 1: Obtain a Groq API Key 1. Go to the [Groq Console](https://console.groq.com/). 2. Navigate to **API Keys** in your account settings. 3. Click **Create API Key** and give it a descriptive name (e.g., “AI Builder”). 4. Copy the generated key. * **Example:** `gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Groq** in your app settings. 2. Paste your **Groq API Key** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can use Groq to deliver ultra-low latency AI responses across workflows and components. ## Step 3: Notes * **Keep your key secure:** Do not hardcode your Groq API key in public code repositories. * **Use environment-specific keys:** Separate dev, staging, and production keys help manage access and security. * **Secure API access:** The key allows your app to interact with Groq endpoints securely and efficiently. # HubSpot Integration Source: http://localhost:3000/docs/ai/integrations/hubspot.md --- tags: Data Infrastructure description: Connect your apps to HubSpot to manage contacts, companies, deals, and marketing workflows. --- The **HubSpot Integration** allows your app to use [HubSpot](https://www.hubspot.com/) as a CRM and marketing automation platform. Once connected, your app can sync leads, manage contacts, update pipelines, and trigger workflows directly from user actions or automated events. ## Step 1: Obtain a HubSpot Access Token 1. Go to your [HubSpot Developer Account](https://developers.hubspot.com/). 2. Navigate to **App → Private Apps** in your account settings. 3. Click **Create Private App**, configure scopes (e.g., `crm.objects.contacts.read/write`, `crm.schemas.companies.read`), and save. 4. Copy the **Access Token** from the Auth tab. * **Example:** `pat-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx` [!HubSpot](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/hubspot.webp) ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add HubSpot** in your app settings. 2. Paste your **HubSpot Access Token** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can sync and manage HubSpot data directly from workflows and UI actions. ## Step 3: Notes * **Keep your token secure:** Do not hardcode your HubSpot token in public code repositories. * **Use environment-specific tokens:** Separate dev, staging, and production tokens to manage access. * **Secure API access:** The token allows your app to interact with HubSpot endpoints securely and efficiently. # Hugging Face Integration Source: http://localhost:3000/docs/ai/integrations/hugging-face.md --- tags: AI description: Connect your apps to Hugging Face to access thousands of open models for text, vision, and multimodal tasks. --- The **Hugging Face Integration** allows your app to use [Hugging Face](https://huggingface.co/) models for a wide range of AI tasks — including text generation, embeddings, translation, classification, image processing, and more. You can integrate both hosted models (via API) or local open-source models through the Transformers library. ## What You Can Do With Hugging Face, your app can: - Access thousands of pre-trained **text, vision, and multimodal models**. - Run **text generation**, summarization, translation, and classification tasks. - Use **embeddings** for search, retrieval, and similarity. - Deploy models locally with `transformers` or connect to hosted inference endpoints. - Fine-tune or customize open models for your specific use cases. - Integrate community and enterprise models seamlessly into workflows. ## Step 1: Obtain a Hugging Face Access Token (Optional) 1. Go to [Hugging Face](https://huggingface.co/). 2. Log in or create a free account. 3. Navigate to **Settings → Access Tokens**. 4. Click **Create New token**, set its scope, and copy it. * **Example:** `hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Hugging Face** in your app settings. 2. Paste your **Hugging Face Access Token** if required. 3. Click **Connect** to validate and save your integration. Once connected, your app can use Hugging Face models directly in workflows, UI actions, or automations. ## Step 3: Notes * **Keep your token secure:** Never expose your Hugging Face token in client-side code. * **Use environment-specific tokens:** Separate dev, staging, and production access. * **Open-source flexibility:** Models can be run fully locally or through Hugging Face’s hosted endpoints. * **Broad ecosystem:** Hugging Face supports thousands of community and commercial models for rapid prototyping and production use. # Langchain Integration Source: http://localhost:3000/docs/ai/integrations/langchain.md --- tags: AI description: Connect your apps to Langchain for advanced AI capabilities. --- The **LangChain Integration** allows your app to leverage the power of [LangChain](https://langchain.com/), a popular open-source framework for building applications with large language models (LLMs). Once connected, your app can orchestrate complex AI workflows, chain together multiple model calls, and integrate with various data sources and tools seamlessly. You can: * **Chain model calls together** to create multi-step reasoning flows. * **Connect multiple providers** (e.g., OpenAI, Anthropic, Gemini, Groq) through a single interface. * **Build intelligent agents** that can use tools, call APIs, or access external data sources dynamically. * **Work with structured data** by combining LLMs with databases, vector stores, and retrieval systems. * **Create RAG (Retrieval-Augmented Generation)** pipelines to ground model outputs in your own data. * **Integrate tools and memory** so models can reason over past interactions and context. * **Deploy reusable components** like prompt templates, chains, and agents for production-grade applications. LangChain essentially acts as a **“glue layer”** between language models, data, and logic — enabling teams to build more **powerful and reliable AI apps** without reinventing core orchestration features. ## Configure the Integration in Your App 1. Click the **Settings** gear icon and navigate to the **Integrations** tab. 2. Find and enable the **LangChain** integration. # Linear Integration Source: http://localhost:3000/docs/ai/integrations/linear.md --- tags: DevTools description: Connect your apps to Linear to manage issues, projects, and sprints directly from workflows. --- The **Linear Integration** allows your app to connect to [Linear](https://linear.app/) to create, update, and track issues and projects seamlessly. Once connected, your app can trigger Linear actions from user interactions or automated workflows. ## What You Can Do With Linear, your app can: - **Create and assign issues** automatically from user actions or AI workflows. - **Update status and priority** of tickets and projects. - **Sync with sprints and cycles** to keep work organized. - **Fetch project and issue data** for dashboards, summaries, or automation. - **Integrate with other tools** like Slack or GitHub through workflows. - Power intelligent workflows (e.g., auto-triage or auto-summarize bug reports). ## Step 1: Obtain a Linear API Key 1. Go to your [Linear account](https://linear.app/). 2. Navigate to **Workspace Settings → API**. 3. Click **Create API Key**, give it a name, and copy the key. * **Example:** `lin_api_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Linear** in your app settings. 2. Paste your **Linear API Key** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can interact with Linear to automate issue tracking and project management. ## Step 3: Notes * **Keep your key secure:** Never expose your Linear API key in client-side code. * **Use environment-specific keys:** Separate dev, staging, and production keys. * **Streamlined workflows:** Automate ticket creation, status updates, and reporting directly from your app. * **Real-time visibility:** Fetch and sync project data to power internal tools or dashboards. # Installation Source: http://localhost:3000/docs/ai/integrations/mcp-installation.md ```python exec import reflex as rx ``` ```md alert warning # The Reflex MCP integration is currently only available for enterprise customers. Please [book a demo](https://reflex.dev/pricing/) to discuss access. ``` To use the Reflex MCP integration, you'll need to configure your AI assistant or coding tool to connect to the Reflex MCP server. No additional Python packages are required on your local machine - the server is hosted and ready to use. ## Prerequisites - An MCP-compatible AI tool (Claude Code, Claude Desktop, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode, Windsurf, etc.) - Internet connection to access the hosted MCP server - Valid Reflex account for OAuth 2.1 authentication ## Authentication The Reflex MCP server uses OAuth 2.1 protocol for secure authentication. You'll need a valid Reflex account, and authentication is handled automatically through your MCP client configuration when you provide your Reflex credentials. ## IDE and Coding Assistant Integration ### Claude Code Add the Reflex MCP server to Claude Code by running: ```bash claude mcp add --transport http reflex https://build.reflex.dev/mcp ``` Then authenticate by running the `/mcp` command inside Claude Code and following the login steps in your browser. Authentication tokens are stored securely and refreshed automatically. See the [Claude Code MCP documentation](https://code.claude.com/docs/en/mcp) for more details. ### Claude Desktop Claude Desktop pulls remote MCP servers from your Claude account's connectors. Go to [claude.ai](https://claude.ai) → **Settings** → **Connectors** → **Add custom connector**, enter `https://build.reflex.dev/mcp` as the URL, and complete the OAuth login. The connector will then be available in Claude Desktop after you sign in. See the [custom connectors guide](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp) for details and plan availability. ### Codex Add the Reflex MCP server to Codex by running: ```bash codex mcp add reflex --url https://build.reflex.dev/mcp ``` See the [Codex MCP documentation](https://developers.openai.com/codex/mcp) for more details. ### Cursor [Click here to install the Reflex MCP server in Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=reflex&config=eyJ1cmwiOiJodHRwczovL2J1aWxkLnJlZmxleC5kZXYvbWNwIn0=), or edit (or create) `~/.cursor/mcp.json` for a global config, or `.cursor/mcp.json` in your project root for a project-specific config: ```json { "mcpServers": { "reflex": { "url": "https://build.reflex.dev/mcp" } } } ``` Open Cursor settings under **MCP & Integrations** to verify the server is connected and complete OAuth login. See the [Cursor MCP documentation](https://cursor.com/docs/context/mcp) for more details. ### Gemini CLI Add the Reflex MCP server to `~/.gemini/settings.json`: ```json { "mcpServers": { "reflex": { "httpUrl": "https://build.reflex.dev/mcp" } } } ``` See the [Gemini CLI MCP documentation](https://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html) for more details. ### GitHub Copilot Create a `.vscode/mcp.json` file in your project root (or open **MCP: Open User Configuration** from the VS Code command palette for a global config): ```json { "servers": { "reflex": { "type": "http", "url": "https://build.reflex.dev/mcp" } } } ``` After saving, start the server from the inline action above the entry in `mcp.json`, then complete the OAuth login when prompted. See the [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/customization/mcp-servers) for more details. ### OpenCode Add the Reflex MCP server to your `opencode.json` (project) or `~/.config/opencode/opencode.json` (global): ```json { "$schema": "https://opencode.ai/config.json", "mcp": { "reflex": { "type": "remote", "url": "https://build.reflex.dev/mcp", "enabled": true } } } ``` See the [OpenCode MCP documentation](https://opencode.ai/docs/mcp-servers/) for more details. ### Windsurf Edit (or create) `~/.codeium/windsurf/mcp_config.json` and add the Reflex server: ```json { "mcpServers": { "reflex": { "serverUrl": "https://build.reflex.dev/mcp" } } } ``` After saving, open Cascade and click the refresh icon in the MCP toolbar to load the new server. See the [Windsurf MCP documentation](https://docs.windsurf.com/windsurf/cascade/mcp) for more details. # Overview Source: http://localhost:3000/docs/ai/integrations/mcp-overview.md ```python exec import reflex as rx ``` ```md alert warning # The Reflex MCP integration is currently only available for enterprise customers. Please [book a demo](https://reflex.dev/pricing/) to discuss access. ``` The Reflex [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) integration provides AI assistants and coding tools with structured access to Reflex framework documentation and component information. This enables intelligent assistance while developing Reflex applications. The Reflex MCP server is deployed at `https://build.reflex.dev/mcp` and provides access to component documentation and Reflex documentation through standardized MCP tools. ## Available Tools The Reflex MCP server provides tools for accessing component documentation and Reflex documentation through standardized MCP capabilities. ## Enterprise Use For enterprise customers requiring on-premises deployment of the Reflex MCP server, please [book a demo](https://reflex.dev/pricing/) to discuss your requirements. # Notion Integration Source: http://localhost:3000/docs/ai/integrations/notion.md --- tags: Data Infrastructure description: Connect your apps to Notion to create, update, and query pages, databases, and documents. --- The **Notion Integration** allows your app to connect to [Notion](https://www.notion.so/) to manage content, automate workflows, and build dynamic interfaces on top of Notion workspaces. Once connected, your app can read and write pages, sync databases, and trigger actions based on user activity. ## What You Can Do With Notion, your app can: - **Create and update pages** in workspaces automatically. - **Read and query databases** to power dashboards, workflows, or automations. - **Sync structured content** like tasks, notes, or documentation with other tools. - Trigger **actions from AI workflows** (e.g., creating meeting notes, logging issues). - Integrate with other services (e.g., Slack, Linear, HubSpot) for seamless collaboration. ## Step 1: Obtain a Notion API Token 1. Go to the [Notion Developers](https://www.notion.so/my-integrations) page. 2. Click **+ New Integration**, give it a name, and copy the generated **Internal Integration Token**. 3. Share the integration with the relevant pages or databases in your workspace to grant access. * **Example:** `ntn_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Notion** in your app settings. 2. Paste your **Notion API Token** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can read and write to Notion directly from workflows and UI actions. ## Step 3: Notes * **Keep your token secure:** Never expose your Notion token in client-side code. * **Use environment-specific tokens:** Separate dev, staging, and production access. * **Granular permissions:** Only share the integration with the pages or databases it needs to access. * **Powerful building block:** Use Notion as a single source of truth for content, tasks, or structured data. # Okta Auth Manager Integration Source: http://localhost:3000/docs/ai/integrations/okta-auth.md --- tags: Authentication description: Use Okta for secure identity and access management via Single Sign-On provisioning. --- The **Okta Auth Manager Integration** allows your app to authenticate users through [Okta](https://okta.com). This integration provides secure OAuth 2.0 / OIDC authentication and supports multi-tenant environments with customizable access policies. ## What You Can Do With Okta, your app can: - Authenticate users securely through Okta’s identity platform. - Enable **SSO** for enterprise users. - Manage user roles, groups, and access permissions. - Protect sensitive data and actions with **OAuth 2.0** and **OpenID Connect (OIDC)**. - Integrate with other identity workflows like MFA or adaptive policies. ## Step 1: Set Up Okta OIDC App Before connecting, you need to create an OIDC application in the Okta Admin Console: 1 - Go to [Okta Admin Console](https://login.okta.com) → **Applications** → **Applications** 2 - Click **Create App Integration** ![Okta Auth 1](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_1.png) 3 - Select **OIDC – OpenID Connect** and choose **Web Application** ![Okta Auth 2](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_2.png) 4 - Configure your app settings: - **Allow wildcard * in sign-in redirect URIs** - **Sign-in redirect URIs** found in the Okta Auth Manager integration settings in AI Builder: `https://{your-sandbox}/authorization-code/callback` - **Sign-out redirect URIs**: `https://{your-sandbox}` - Assign to the correct **Group** or **Everyone** depending on your access control ![Okta Auth 3](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_3.png) 5 - Save the app integration. 6 - Copy your **Client ID** (`OKTA_CLIENT_ID`) and **Client Secret** (`OKTA_CLIENT_SECRET`) from the app settings. ![Okta Auth 4](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_4.png) ## Step 2: Finding Your Okta Issuer URI 1. In the Okta Admin Console, go to **Security** → **API** → **Authorization Servers** 2. Click on the **default** server and copy the **Issuer URI**. 3. Remove the trailing `/oauth2/default` from the URI to get your **Okta Issuer URI** (`OKTA_ISSUER_URI`). Example: If your Issuer URI is `https://{yourOktaDomain}.okta.com/oauth2/default` Use `https://{yourOktaDomain}.okta.com` ![Okta Auth 5](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/okta_auth_5.png) > **Note:** Always use separate Okta apps for dev, staging, and production environments to avoid mixing credentials. ## Step 3: Configure the Integration 1. Go to the **Integrations** section in your app settings by clicking **`@`** and then selecting the **Integrations** tab. 2. Click **Add** next to **Okta Auth Manager**. 3. Fill in the credential fields: - Enter your Okta Client ID - Enter your Okta Client Secret - Enter your Okta Issuer URI 4. Click **Connect** to save the integration. Your app can now authenticate users through Okta using the secure OAuth 2.0 / OIDC flow. # OpenAI Integration Source: http://localhost:3000/docs/ai/integrations/openai.md --- tags: AI description: Connect to OpenAI's powerful language models for text generation, analysis, and more. --- The **OpenAI Integration** allows your app to use OpenAI APIs for features such as text generation, embeddings, and other AI-powered functionality. ## Step 1: Obtain an OpenAI API Key 1. Go to the [OpenAI Platform](https://platform.openai.com/). 2. Navigate to **API Keys** in your account settings. 3. Click **Create new secret key**. 4. Copy the generated key. - Example: `sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add OpenAI Integration** in your app settings. 2. Enter your **OpenAI API Key** in the input field. 3. Save the integration. Your app is now ready to make OpenAI API requests. --- ## Step 3: Notes - Keep your OpenAI key secure; do **not** hardcode it in public code repositories. - Use environment-specific secrets if you have separate development, staging, and production environments. - The key allows your app to interact with OpenAI endpoints securely and efficiently. # Overview Source: http://localhost:3000/docs/ai/integrations/overview.md ```python exec from reflex_docs.pages.integrations.integration import integration_page ``` ```python eval integration_page() ``` # Perplexity Integration Source: http://localhost:3000/docs/ai/integrations/perplexity.md --- tags: AI description: Connect your apps to Perplexity to power real-time, retrieval-augmented AI experiences. --- The **Perplexity Integration** allows your app to use [Perplexity](https://www.perplexity.ai/) to deliver fast, accurate, retrieval-augmented answers from the web and trusted sources. Once connected, you can use Perplexity to enhance search, summarization, and real-time knowledge in your workflows. ## What You Can Do With Perplexity, your app can: - **Retrieve real-time information** from the web to ground model outputs. - **Generate concise summaries** and answers with citations. - Power **search experiences**, research assistants, and contextual AI features. - **Combine Perplexity with other models** for hybrid workflows (e.g., retrieval + reasoning). - Enable **trusted, source-backed outputs** for more accurate responses. ## Step 1: Obtain a Perplexity API Key 1. Go to the [Perplexity](https://www.perplexity.ai/). 2. Log in or create an account. 3. Navigate to **Account → API → [API Keys](https://www.perplexity.ai/account/api/keys)**. 4. Click **Generate Key** and copy the generated key. * **Example:** `pplx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Perplexity** in your app settings. 2. Paste your **Perplexity API Key** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can use Perplexity for retrieval-augmented AI features across workflows and components. ## Step 3: Notes * **Keep your key secure:** Do not hardcode your Perplexity API key in public code repositories. * **Use environment-specific keys:** Separate dev, staging, and production keys for better control. * **Secure API access:** The key allows your app to interact with Perplexity endpoints securely and efficiently. * **Real-time power:** Perplexity is ideal for use cases where freshness and factual grounding matter. # Replicate Integration Source: http://localhost:3000/docs/ai/integrations/replicate.md --- tags: AI description: Connect your apps to Replicate to run and deploy open-source machine learning models with ease. --- The **Replicate Integration** allows your app to use [Replicate](https://replicate.com/) to run open-source AI models in the cloud without managing infrastructure. Once connected, you can use Replicate to generate text, images, audio, and more — directly from workflows and UI actions. ## What You Can Do With Replicate, your app can: - Run open-source **AI models** without GPU or hosting setup. - Access models for **text generation**, **image generation**, **audio**, and **multimodal tasks**. - Automate workflows like content generation, data processing, or AI-powered features. - Use prebuilt models or deploy your own custom models. - Scale effortlessly with serverless infrastructure. ## Step 1: Obtain a Replicate API Token 1. Go to the [Replicate Dashboard](https://replicate.com/account). 2. Log in or create an account. 3. Navigate to the **API Tokens** section. 4. Copy your **API Token** from the account page. * **Example:** `r8_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Replicate** in your app settings. 2. Paste your **Replicate API Token** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can call Replicate models directly in workflows, UI actions, or automations. ## Step 3: Notes * **Keep your token secure:** Do not hardcode your Replicate token in public code repositories. * **Use environment-specific tokens:** Separate dev, staging, and production environments for security. * **Secure API access:** The token allows your app to interact with Replicate endpoints safely and efficiently. * **Model flexibility:** You can use community models or deploy your own for full control. # Resend Integration Source: http://localhost:3000/docs/ai/integrations/resend.md --- tags: Communication description: Send transactional and automated emails directly from your AI-generated applications using Resend. --- The **Resend Integration** allows your AI-generated apps to send emails directly from workflows, user actions, or automated triggers — perfect for notifications, confirmations, or any email-based communication your app needs. ## What You Can Do With the Resend Integration, your app can: - Send automated transactional emails - Notify users of important events (signups, job completions, etc.) - Integrate email sending into AI workflows - Use dynamic variables in your message body (e.g. user name, order ID) ## Step 1: Get Your Resend API Key 1. Go to [Resend](https://resend.com/). 2. Log in or create a free account. 3. Navigate to **API Keys** from the dashboard sidebar. 4. Click **Create API Key**, give it a name (e.g. “AI Builder”), and copy it. - Example: `re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Open your app in the **AI Builder**. 2. Click the **Settings** gear icon and navigate to the **Integrations** tab. 3. Find and enable the **Resend** integration. 4. Paste your **API Key** in the input field. 5. Click **Connect** to confirm the connection. # Roboflow Integration Source: http://localhost:3000/docs/ai/integrations/roboflow.md --- tags: AI description: Connect your apps to Roboflow to use computer vision models and datasets for image detection, classification, and segmentation. --- The **Roboflow Integration** allows your app to use [Roboflow](https://roboflow.com/) to run and deploy computer vision models without complex infrastructure. Once connected, you can use Roboflow to power image detection, object tracking, classification, and segmentation workflows. ## What You Can Do With Roboflow, your app can: - Run **pre-trained computer vision models** for detection, classification, or segmentation. - Deploy and use **custom-trained models** built in Roboflow. - Automate workflows that rely on visual inputs — e.g., quality checks, object detection, image analysis. - Ingest and process **images in real time**. - Combine vision outputs with other integrations (e.g., AI reasoning, automation flows). ```md alert ## This integration currently supports image inputs only. Video and streaming inputs are not yet supported. ``` ## Step 1: Obtain a Roboflow API Key 1. Go to your [Roboflow Account](https://roboflow.com/). 2. Navigate to **Settings → API Keys**. 3. Copy your Private API Key. ## Step 2: Set up your Model in Roboflow 1. Go to Workflows and create a new workflow. 2. Set up the workflow you want to use in your app, ensuring that it takes an image as input. 3. Click the `deploy` button, select `Images` and then select `Integrate with my app or website`. 4. Copy the `workspace_name` and `workflow_id` from the provided code snippet. [!Roboflow](https://raw.githubusercontent.com/reflex-dev/integrations-docs/refs/heads/main/images/docs/roboflow.webp) ## Step 3: Configure the Integration in Your App 1. Go to **Integrations → Add Roboflow** in your app settings. 2. Paste your **Roboflow API Key**, **Workspace Name**, and **Workflow ID** in the input fields. 3. Click **Connect** to validate and save your integration. Once connected, your app can call Roboflow models directly from workflows, UI actions, or automated triggers. ## Step 4: Notes * **Keep your key secure:** Never expose your Roboflow key in client-side code. * **Use environment-specific keys:** Separate dev, staging, and production keys to control access. * **Model flexibility:** Use community models or your own custom-trained models. * **Real-time vision:** Ideal for applications involving cameras, inspection, monitoring, or visual AI. # Skills Source: http://localhost:3000/docs/ai/integrations/skills.md ```python exec import reflex as rx def _summary_card(kicker: str, title: str, body: str) -> rx.Component: return rx.el.div( rx.el.div(kicker, class_name="text-xs font-semibold uppercase text-primary-10"), rx.el.h3(title, class_name="text-base font-semibold text-secondary-12"), rx.el.p(body, class_name="text-sm leading-6 text-secondary-11"), class_name="flex flex-col gap-2 rounded-lg border border-secondary-a4 bg-white-1 p-4", ) def skills_summary_cards() -> rx.Component: return rx.el.div( _summary_card( "Docs", "Current Reflex guidance", "Point agents to the right Reflex docs for state, vars, components, routing, styling, deployment, and more.", ), _summary_card( "Setup", "Python environment workflow", "Teach agents how to create a virtual environment, install Reflex, and initialize a new project safely.", ), _summary_card( "Runtime", "Process management", "Give agents a repeatable way to compile, run, restart, and debug Reflex apps without guessing at processes.", ), _summary_card( "Context", "Pairs well with MCP", "Use skills for durable local instructions and MCP for structured lookup of current docs and component data.", ), class_name="grid grid-cols-1 gap-3 md:grid-cols-2 my-6", ) ``` Reflex Agent Skills give AI coding assistants up-to-date guidance for building Reflex applications. They package Reflex-specific knowledge, setup steps, and process-management workflows into reusable `SKILL.md` files that agents can load when the conversation or codebase calls for them. The skills are maintained in the [reflex-dev/agent-skills](https://github.com/reflex-dev/agent-skills) repository and are designed for agents that support the Agent Skills standard, including Claude Code, Cursor, OpenCode, OpenAI Codex, and Pi. ```python eval skills_summary_cards() ``` ## When to Use Skills Use Reflex Agent Skills when you want an AI assistant to follow Reflex-specific workflows instead of relying only on general training data. They are especially useful when an assistant needs to: - Build or edit a Reflex app. - Set up a new Python environment. - Decide which Reflex docs apply to the task. - Compile, run, restart, or debug a local Reflex server. - Keep generated code aligned with current Reflex patterns. Skills load contextually. For example, when an assistant sees a Python file importing `reflex as rx`, it can load the Reflex docs skill. When you ask it to start a new app, it can load the Python environment setup skill before running project commands. ## Skills vs MCP Skills and MCP solve related but different problems. For the best experience, use both. ```md definition # Skills Local instruction packs that tell the agent how to work with Reflex, which workflows to follow, and which references matter for common development tasks. # MCP Structured runtime access to Reflex documentation and component information through a hosted server. Use it when an agent or editor can call MCP tools directly. ``` ```md alert info # Use Skills for durable local guidance. Use MCP for structured documentation lookup and richer tool-assisted context. ``` ## Installation Choose the install path that matches your assistant. `````md tabs ## Claude Code Install the plugin from the Claude Code plugin marketplace: ```text /plugin marketplace add reflex-dev/agent-skills /plugin install reflex@reflex-agent-skills ``` Restart or refresh Claude Code after installation if the skills do not appear immediately. ## Cursor Install from the Cursor Marketplace, or add the repository manually from: ```text reflex-dev/agent-skills ``` In Cursor, add it through **Settings > Rules > Add Rule > Remote Rule (GitHub)**. ## CLI If your environment supports the `skills` CLI, install the package with: ```bash npx skills add reflex-dev/agent-skills ``` Use the CLI's update command later to keep the skill pack current. ## Manual Clone the repository: ```bash git clone https://github.com/reflex-dev/agent-skills.git ``` Then copy the folders inside `skills/` into the appropriate location: | Agent | Skill Directory | | --- | --- | | Claude Code | `~/.claude/skills/` | | Cursor | `~/.cursor/skills/` | | OpenCode | `~/.config/opencode/skills/` | | OpenAI Codex | `~/.codex/skills/` | | Pi | `~/.pi/agent/skills/` | Copy the skill folders themselves, not the parent `skills/` directory. ````` ## Included Skills The Reflex skill pack includes three core skills. `````md tabs ## Docs The `reflex-docs` skill gives the assistant a Reflex-specific reference map and a summary of the framework's core concepts. ### Use this skill when the assistant is: - Building full-stack Python web apps with Reflex. - Writing files that import `reflex` or use the `rx` namespace. - Creating components. - Managing state, vars, computed vars, or event handlers. - Working with routing, styling, database models, assets, authentication, client storage, API routes, custom components, or wrapped React components. ### It points the assistant to docs for: - Core app structure: getting started, components, state and vars, events, pages, and routing. - UI and styling: styling, assets, the component library, and recipes. - Backend features: database models, authentication, client storage, API routes, and API reference. - Advanced integrations: custom components and wrapped React components. It also reminds the assistant to prefer current Reflex documentation over pre-trained knowledge when there is a conflict. ## Setup The `setup-python-env` skill guides the assistant through setting up a Python environment for a Reflex app. ### Use this skill when: - Starting a new Reflex project. - Setting up a development environment. - There is no `.venv` directory. - Reflex imports fail because dependencies are missing. ### Preferred workflow: ```bash uv venv .venv source .venv/bin/activate uv add reflex reflex init ``` If `uv` is not available, the skill falls back to: ```bash python3 -m venv .venv source .venv/bin/activate pip install --upgrade pip pip install reflex reflex init ``` The workflow checks for an existing `.venv`, verifies Python 3.10 or newer, and installs Reflex only when needed. ## Process The `reflex-process-management` skill teaches the assistant how to compile, run, reload, and debug Reflex apps. ### Use this skill when: - Testing that a Reflex app compiles. - Starting a local Reflex server. - Restarting a server after code changes. - Reading logs to diagnose app errors. ### Validation command: ```bash reflex compile --dry ``` ### Run command: ```bash reflex run --env prod --single-port 2>&1 | tee reflex.log ``` Production mode does not hot reload. To apply code changes, the assistant should stop the listening process for the app port and restart the server: ```bash lsof -i : -sTCP:LISTEN -t kill -INT $(lsof -i : -sTCP:LISTEN -t) ``` Using `-sTCP:LISTEN` helps the assistant target the server process instead of browser connections. ````` ## Recommended Workflow `````md tabs ## New App 1. Install Reflex Agent Skills in your assistant. 2. Ask the assistant to create or initialize a Reflex app. 3. The assistant should load `setup-python-env`. 4. After the environment is ready, the assistant can run `reflex init`. 5. As the app is built, the assistant should use `reflex-docs` for current framework guidance. 6. Before handing the app back, the assistant should use `reflex-process-management` to compile or run the project. ## Existing 1. Open your Reflex project in an agent-enabled editor. 2. Ask for the feature, bug fix, or refactor you want. 3. The assistant should load `reflex-docs` when it sees Reflex code. 4. For local verification, the assistant should compile the app with `reflex compile --dry` or run it with the process-management workflow. ## Debugging 1. Ask the assistant to inspect the error. 2. The assistant should read `reflex.log` if the app was started through the process-management workflow. 3. The assistant should identify the failing import, component, event handler, route, or state update. 4. After applying a fix, the assistant should restart the app if it is running in production mode. ````` ## Keeping Skills Updated Because Reflex evolves quickly, update the skill pack regularly. If you installed through a marketplace or skills CLI, update through that same tool. If you cloned the repository manually, pull the latest changes: ```bash cd agent-skills git pull ``` Then copy the updated skill folders back into your assistant's skills directory if your setup does not read directly from the cloned repository. ## Troubleshooting `````md tabs ## Loading Check that: - Your assistant supports Agent Skills. - The skill folders are in the correct skills directory. - Each skill folder contains a `SKILL.md` file. - The assistant was restarted or refreshed after installation if required. ## Outdated Advice Ask the assistant to use the Reflex docs skill, or pair the skill pack with the Reflex MCP integration for structured access to current docs and component information. ## Commands Ask the assistant to follow the `setup-python-env` skill again and verify: - The virtual environment is active. - Python is version 3.10 or newer. - Reflex is installed in the active environment. - The command is being run from the project root. ## App Updates If the app was started with `--env prod`, it will not hot reload. Restart the server with the `reflex-process-management` workflow. ````` ## Contributing Each skill lives in `skills//` and contains a `SKILL.md` manifest. To contribute new guidance, update or add a skill in the [reflex-dev/agent-skills](https://github.com/reflex-dev/agent-skills) repository and follow the [Agent Skills spec](https://agentskills.io/) for the skill format. # Stripe Integration Source: http://localhost:3000/docs/ai/integrations/stripe.md --- description: Connect your apps to Stripe to accept payments, manage subscriptions, and handle billing securely. --- The **Stripe Integration** allows your app to use [Stripe](https://stripe.com/) to power secure payments, subscriptions, and billing workflows. Once connected, you can process transactions, manage customers, and trigger payment flows directly from your app. ## What You Can Do With Stripe, your app can: - **Accept one-time payments** or set up **recurring subscriptions**. - **Manage customers**, payment methods, and invoices. - Handle **refunds, payment confirmations**, and notifications. - Automate billing flows and webhook-based actions. - Build secure, PCI-compliant checkout experiences with ease. ## Step 1: Obtain a Stripe API Key 1. Go to your [Stripe Dashboard](https://dashboard.stripe.com/). 2. Navigate to **Developers → API Keys**. 3. Copy your **Secret Key** (or create a restricted key for added security). * **Example:** `sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` > 💡 Use test keys in development environments and live keys in production. ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Stripe** in your app settings. 2. Paste your **Stripe API Key** in the input field. 3. Click **Connect** to validate and save your integration. Once connected, your app can process payments and manage billing directly from workflows and UI actions. ## Step 3: Notes * **Keep your API key secure:** Never expose your Stripe key in client-side code. * **Use environment-specific keys:** Test keys for staging, live keys for production. * **Secure transactions:** All payment processing is handled through Stripe’s PCI-compliant infrastructure. # Supabase Integration Source: http://localhost:3000/docs/ai/integrations/supabase.md --- tags: Data Infrastructure description: Connect your apps to Supabase to use a hosted Postgres database with real-time capabilities and powerful APIs. --- The **Supabase Integration** allows your app to connect to [Supabase](https://supabase.com/) — a hosted Postgres database with real-time subscriptions, authentication, and file storage. Once connected, your app can query and update data securely, power dashboards, and sync workflows in real time. ## What You Can Do With Supabase, your app can: - **Read and write data** using Postgres through a simple REST or client API. - Enable **real-time updates** that sync automatically to your UI. - Use **row-level security** and access control for safe data management. - Store and retrieve files with Supabase Storage. - Integrate seamlessly with AI, dashboards, or internal tools. ## Step 1: Obtain Your Supabase URL and Key 1. Go to your [Supabase Project](https://supabase.com/). 2. Choose the project you want to connect. 3. Navigate to **Project Settings**. 4. Go to **Data API** and copy your `Supabase_URL`. 5. Then go to **API Keys** and copy your `Supabase_Key` (the secret key). * **Example URL:** `https://your-project.supabase.co` * **Example Key:** `sb_xxxxxxxxxxxxxxxxxxxxxxxxxxxx.` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Supabase** in your app settings. 2. Paste your **Supabase URL** and **Supabase Key** into the fields. 3. Click **Connect** to validate and save your integration. Once connected, your app can query and update your Supabase database directly from workflows and UI actions. ## Step 3: Notes * **Keep your keys secure:** Never expose the `Supabase_Key` key in client-side code. * **Use environment-specific keys:** Separate dev, staging, and production projects for clean access control. * **Realtime support:** Supabase enables live syncing of data changes. * **Row-level security:** Make sure to configure policies appropriately for your use case. # Twilio Integration Source: http://localhost:3000/docs/ai/integrations/twilio.md --- tags: Communication description: Connect your apps to Twilio to send SMS, WhatsApp messages, and voice calls programmatically. --- The **Twilio Integration** allows your app to use [Twilio](https://www.twilio.com/) to send and receive SMS, WhatsApp messages, and voice calls. Once connected, your app can trigger messages or calls directly from workflows, user actions, or automated events. ## What You Can Do With Twilio, your app can: - **Send SMS** messages to users or customers globally. - **Send and receive WhatsApp messages**. - **Make and manage voice calls** programmatically. - Automate **notifications**, **alerts**, and **transactional messages**. - Integrate messaging into AI workflows for dynamic, real-time communication. ## Step 1: Obtain Twilio Credentials 1. Go to your [Twilio Console](https://www.twilio.com/console). 2. Copy your **Account SID** and **Auth Token** from the dashboard. * **Example Account SID:** `ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` * **Example Auth Token:** `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` ## Step 2: Configure the Integration in Your App 1. Go to **Integrations → Add Twilio** in your app settings. 2. Paste your **Account SID** and **Auth Token** in the input fields. 3. Click **Connect** to validate and save your integration. Once connected, your app can send messages or make calls through Twilio directly in workflows and components. ## Step 3: Notes * **Keep your credentials secure:** Never expose your Auth Token in client-side code. * **Use environment-specific credentials:** Separate dev, staging, and production credentials. * **Phone number setup:** Ensure you’ve configured a valid Twilio number for sending messages or calls. * **Regulatory compliance:** Review Twilio’s messaging and voice compliance requirements for your region. # Reflex Build: Best Practices Source: http://localhost:3000/docs/ai/overview/best-practices.md > A comprehensive guide to working effectively with AI Builder. This guide outlines how to get the most reliable and efficient results when working with the AI Builder inside Reflex Build. The key to success is clarity, structure, and iteration. --- ## Core Workflow ### Foundation: Planning Before You Build Before jumping into the AI Builder, take time to plan your approach. Good preparation leads to better results and fewer iterations. - **Define your core purpose and users** — Write a 2-3 sentence app description and identify your target users and their needs. - **Prioritize 3-5 key features** — Focus on the most important functionality first, then expand from there. - **Gather visual references** — Collect screenshots, wireframes, or sketches of layouts you want to emulate. - **Structure your data** — List what information each page needs to display and how users will interact with it. - **Start with your most important page** — Usually your main dashboard, home screen, or primary workflow. Get this right first. ### Auto-Generate Prompts from App Specs To save time and get higher-quality prompts, you can feed your full app spec into the AI Builder and ask it to break the spec into structured, build-ready prompts. The AI Builder can translate your vision into: - Layout instructions - UI component definitions - Data model requirements - Styling preferences - Follow-up test plans **Example workflow:** 1. Paste your full app specification into the AI Builder 2. Ask **"Break this into a series of buildable prompts."** 3. Execute each generated prompt in sequence 4. Build iteratively using the structured prompts ### Working with Text Specifications If you have a structured app specification, don't paste the entire document into the builder at once. Break it down into logical sections and feed them in sequence. **Pro tip:** Let the AI Builder help prepare prompts: Paste your full app spec and ask: - **"Break this into buildable prompts."** - **"Write one prompt per feature/page to build this app."** This approach — planning first, then building iteratively — lets you move faster and build smarter. ### Writing Clear, Task-Oriented Prompts The AI performs best when it receives **specific, outcome-driven instructions**. Avoid vague, broad prompts. ```diff - Build me an admin dashboard. # <- Bad + Create a 2-column layout with a sidebar for navigation and a top navbar. # <- Good ``` Whenever possible, split large tasks into smaller steps: - Define the layout first (columns, rows, sidebar) - Add UI components (buttons, inputs, modals) - Handle data models and states later - Use follow-ups to style and polish Use precise styling language, for example: ```diff - Grid items have small spacing and sharp corners. + Add medium spacing between grid items and use large rounded corners on cards. ``` Avoid subjective terms like "**nice**," "**modern**," or "**clean**." Treat your prompt as interface documentation for the builder. ### Working with Images and Visual References You can drop in screenshots of websites, dashboards, apps, or even hand-drawn wireframes. The builder will extract layout, design, and functionality ideas from these images. **Tips for images:** - Clear screenshots work best - Include any elements you want: forms, tables, nav, charts - You can annotate them with arrows, notes, or labels **Get UI/UX feedback:** Upload a screenshot and ask: **"What are 5 things I could do to improve the UI/UX of this?"** Follow up with: **Implement items 1, 2, and 4.** Or request specific improvements: **Make this more minimal and mobile-first.** --- ## Optimizing Your Workflow ### Building Iteratively Trying to generate your full app in a single prompt almost never works well. Instead, approach your build in clear stages: 1. **Layout** — Grid, Flex, responsive columns/rows 2. **Components** — Tables, buttons, modals, charts, etc. 3. **State** — Bindings, stores, mock data 4. **Refinement** — Tweaks, visual polish, edge case handling At each stage, give feedback and iterate. If the AI builder makes something close, you can say: ```diff - Modal is included and sidebar is static. + Remove modal and make sidebar collapsible. - Buttons vary across pages. + Use same button style from home page. - Card layout differs across sections. + Repeat card layout from dashboard section. ``` ### Improving UI/UX To improve your design, ask the builder for more polished layouts, better structure, or more modern styles. ```diff - Layout feels cluttered with small headings and dense sections. + Increase heading sizes and spacing between sections for better hierarchy. - Navigation buttons are inconsistent. + Standardize button sizes and colors for consistent UX. ``` **Suggested workflow:** 1. Upload an image or describe the layout. 2. Ask: **"Tell me 5 things that would improve the UI/UX of this page."** 3. Review the suggestions and decide which ones you want to apply. 4. Implement: **"Improve visual hierarchy by increasing heading sizes and adding more spacing between sections."** ### Using Knowledge to Guide the Build The **Knowledge** panel lets you provide long-form references that influence how the agent builds your app. Add design systems, style guides, brand guidelines, or architecture rules. Once added, the builder will try to honor these rules throughout the session, ensuring consistency without repeating instructions. Try combining Knowledge with your prompts: - **Use the style guide in Knowledge to improve this page.** - **Is the current layout aligned with our design system in Knowledge?** ### Local Development Integration We have an MCP server available for enterprise customers to connect local AI development tools such as Claude Desktop, Windsurf, or Codex. This enables a hybrid workflow: generate your app and make major changes in the App Builder, then move to local development for detailed refinements and custom functionality. > **Enterprise Feature:** The Reflex MCP integration is currently only available for enterprise customers. [Book a demo](https://reflex.dev/pricing/) to discuss access. #### Quick Setup **Prerequisites:** - MCP-compatible AI tool (Claude Desktop, Windsurf, Codex) - Valid Reflex account for OAuth authentication - Internet connection to the hosted MCP server **Benefits:** - **Seamless handoff** — Move between web builder and local development - **AI-powered local development** — Use your preferred AI tools with Reflex projects - **No local installation** — Hosted MCP server requires no additional Python packages - **Secure authentication** — OAuth 2.1 integration with your Reflex account For complete setup instructions for Claude Desktop, Windsurf, Codex, and other MCP clients, visit our [MCP integration](https://reflex.dev/docs/ai/integrations/mcp-installation/) documentation. --- ## Key Takeaways - **Plan before you build**. A few minutes of preparation saves hours of iteration. - **Think modularly**. Focus on atomic parts before the full system. - **Write like a designer-developer**. Clear, structural, and functional language wins. - **Iterate continuously**. Let each prompt get you 80% there, then refine. With these techniques, the AI Builder becomes a reliable extension of your creative and technical intent. # Templates Source: http://localhost:3000/docs/ai/overview/templates.md Reflex has many certified templates, seen on the `Trending` tab of the Reflex Build, that can be used to kickstart your app. ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/overview/templates_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## Using a Template To use a template, simply click the template and then in the bottom right corner of the app click the `Fork` button. This will create a copy of the template in your own account. You can then edit the app as you like with further prompting. ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/overview/fork_template_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` Templates are great to get started if they have similar UI to what you are looking to build. You can then add your own data to the app. # Your First Reflex Build App Source: http://localhost:3000/docs/ai/overview/tutorial.md In this tutorial, you'll build a data dashboard application that displays employee information in both table and chart formats, with interactive features for filtering and adding new data. We'll also add a simple chatbot page to demonstrate multi-page navigation. ## What You'll Build By the end of this tutorial, you'll have created: - A dashboard displaying employee data in a table and bar chart - Interactive filtering to search through your data - A modal form for adding new employees - A separate page with a simple chatbot interface This tutorial assumes you're starting with a new project in AI Builder. --- ## Creating Your Dashboard Let's start by building the core of our application - a dashboard that displays employee data. **Prompt:** ``` Create a dashboard page with a table showing sample employee data with columns: Name, Department, and Salary. Below the table, add a bar chart that visualizes the salary data. Include at least 5 sample employees with different departments and salary ranges. ``` This will create your main dashboard page with both tabular and visual representations of your data. The AI will generate sample employee records and create a bar chart that makes it easy to compare salaries across your team. ```python exec import reflex as rx ``` ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/overview/tutorial_1_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## Adding Interactive Filtering Now that you have your basic dashboard, let's make it more interactive by adding the ability to filter and search through your employee data. **Prompt:** ``` Add filtering functionality to the employee table. Include a search input above the table that filters rows based on name, and dropdown filters for department. Make sure the filters work together and update the table in real-time. ``` Your dashboard now becomes much more useful with real-time filtering. Users can quickly find specific employees by name or narrow down results by department. The filters work together, so you can combine a department filter with a name search. ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/overview/tutorial_2_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## Enabling Data Entry A static dashboard is useful, but being able to add new data makes your app much more practical. Let's add the ability to create new employee records. **Prompt:** ``` Add an "Add Employee" button above the table. When clicked, open a modal with input fields for Name, Department, and Salary. When the form is submitted, add the new employee to the table and update the bar chart. Include form validation for required fields. ``` Your app now has full CRUD capability for employee records. The modal form provides a clean interface for data entry, and both your table and chart update immediately when new employees are added. ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/overview/tutorial_3_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## Building a Multi-Page App Most real applications have multiple pages. Let's add a chatbot page to demonstrate navigation and create a more complete user experience. **Prompt:** ``` Create a new page called "Chat" and add it to the navigation. Build a simple chatbot interface with a message input field, send button, and chat history display. For now, make the bot echo back the user's messages with "Bot says: [user message]". ``` Your app now has proper navigation between the dashboard and chat functionality. The chatbot page demonstrates how easy it is to add new features and pages to your AI Builder application. ```python eval rx.el.div( rx.image( src="https://web.reflex-assets.dev/ai_builder/overview/tutorial_4_light.avif", class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full flex flex-col rounded-md", ) ``` ## What's Next? You've successfully built a complete web application with data visualization, interactive filtering, data entry, and multi-page navigation. Your app demonstrates many common patterns used in modern web applications: - **Data presentation** with tables and charts - **User interaction** through filtering and forms - **Real-time updates** when data changes - **Multi-page architecture** with navigation ## Exploring Further Now that you have a working foundation, try experimenting with these ideas: - **Customize the data model** - change the employee fields or add new columns - **Enhance the visualizations** - try different chart types or add more charts - **Improve the chatbot** - give it more sophisticated responses or integrate it with your employee data - **Add more pages** - create additional features like employee profiles or reporting dashboards The power of AI Builder is that you can iterate quickly with natural language prompts. Each new feature is just a conversation away! # What Is Reflex Build Source: http://localhost:3000/docs/ai/overview/what-is-reflex-build.md Reflex Build is an AI-powered platform that lets anyone create full-stack web apps just by describing ideas in plain English—no coding needed. It includes a full-fledged built-in IDE, real-time collaboration, and project sharing—all in your browser, no installation required. ```python exec import reflex as rx landing_features = [ { "title": "Database Integration", "description": "Automatically integrate your database\ninto your application with ease", "icon": "database", }, { "title": "Secure Secrets", "description": "Safely manage your API keys and tokens\nwith a built in secrets manager", "icon": "shield", }, { "title": "Live Preview", "description": "See all application changes in real-time\nwith our interactive preview tab", "icon": "eye", }, { "title": "Quick Download", "description": "Download your complete project files\nwith just a single click operation", "icon": "download", }, { "title": "Easy Deployment", "description": "Deploy your application to production\nwith just a single click process", "icon": "rocket", }, { "title": "Manual File Editing", "description": "Edit your project files directly\nwith our intuitive code editor", "icon": "code", }, { "title": "AI Package Manager", "description": "Let AI handle your package installations\nvia natural prompting", "icon": "sparkles", }, { "title": "Smart Prompting", "description": "Get better development results\nwith AI-optimized prompt templates", "icon": "message-circle", }, ] features_data = [ { "title": "Project Menu Bar", "subtitle": "Browse previously built applications, create new sessions, store database variables, and much more!", "img": "https://web.reflex-assets.dev/ai_builder/what_is_reflex_build/project_bar_light.avif", }, { "title": "Chat Area", "subtitle": "See your prompts in action with visual cues, editing notifications, and file generations every step of the way.", "img": "https://web.reflex-assets.dev/ai_builder/what_is_reflex_build/chat_light.avif", }, { "title": "Application Workspace", "subtitle": "Your workspace contains all the folders and files of your application. You can add new files and folders as well!", "img": "https://web.reflex-assets.dev/ai_builder/what_is_reflex_build/file_tree_light.avif", }, { "title": "Code Editor", "subtitle": "The code editor displays the current selected file. You can edit the code directly and save it instantly.", "img": "https://web.reflex-assets.dev/ai_builder/what_is_reflex_build/code_light.avif", }, { "title": "Integrations", "subtitle": "Easily connect with the tools your team already uses or extend your app with any Python SDK, library, or API.", "img": "https://web.reflex-assets.dev/ai_builder/what_is_reflex_build/integrations_light.avif", }, { "title": "Plan", "subtitle": "Plan your application's development with the AI Builder. You can add or remove phases and tasks as you go.", "img": "https://web.reflex-assets.dev/ai_builder/what_is_reflex_build/plan_light.avif", }, { "title": "Top Menu Bar", "subtitle": "This menu contains the main views of the application. Preview, Code, Plan, Integrations, Knowledge, Secrets and Settings. You can also see the current workspace RAM and CPU usage. Deploy, copy or share your application with the buttons in the top right corner.", "img": "https://web.reflex-assets.dev/ai_builder/what_is_reflex_build/top_light.avif", }, { "title": "Preview Tab", "subtitle": "The preview tab showcases a live application. You can navigate to other applications directly from this tab, refresh the app, and even view it in full screen.", "img": "https://web.reflex-assets.dev/ai_builder/what_is_reflex_build/preview_light.avif", }, ] def feature_card(feature: dict) -> rx.Component: return rx.el.div( rx.el.div( rx.el.span( rx.icon( tag=feature["icon"], size=15, class_name="inline-block mr-2 text-primary-11", ), rx.el.span(f"{feature['title']}"), class_name="text-sm font-semibold flex flex-row items-center pt-5 px-2 text-secondary-12", ), rx.el.span( feature["description"], class_name="text-sm font-medium block align-center px-2 text-secondary-11", ), class_name="flex flex-col gap-2", ), class_name="w-full rounded-md", ) def _docs_features() -> rx.Component: return rx.el.div( rx.el.div( rx.foreach(landing_features, feature_card), class_name="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-2 gap-4", ), class_name="flex flex-col w-full h-full justify-start align-start items-start py-4 gap-x-4 z-[99]", ) def _docs_app_section_features_small_screen(feature: dict): return rx.el.div( rx.image( src=feature["img"], class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), rx.el.div( rx.el.label( feature["title"], class_name="text-sm font-bold cursor-pointer" ), rx.el.label( feature["subtitle"], class_name="text-sm font-light cursor-pointer" ), class_name="flex flex-col px-1 py-2", ), class_name="w-full flex flex-col rounded-md", ) def _docs_app_section_toggles(feature: dict): return rx.el.div( rx.el.label(feature["title"], class_name="text-sm font-bold"), rx.el.label(feature["subtitle"], class_name="text-sm font-light"), class_name="w-full flex flex-col max-w-md rounded-md p-4", ) def _docs_app_sections(): return rx.el.div( rx.el.div( rx.el.div( rx.el.label( "Small details, big impact", class_name="text-sm font-light" ), rx.el.label( "Made With Exceptional Care", class_name="text-3xl font-bold" ), rx.el.label( "Every feature in Reflex Build is carefully crafted to set new standards. Mediocre isn't an option.", class_name="text-md font-regular", ), class_name="flex flex-col w-full max-w-lg gap-y-1", ), rx.foreach( features_data[:5], lambda feature: _docs_app_section_toggles(feature), ), class_name="flex flex-col gap-y-4 justify-start max-w-sm", ), rx.el.div( rx.image( src=features_data[0]["img"], class_name="rounded-md h-auto", border=f"0.81px solid {rx.color('slate', 5)}", ), class_name="w-full max-w-4xl", ), class_name="flex flex-row w-full h-full justify-between align-center items-center py-4 gap-x-4 z-[99]", display=["none" if i <= 4 else "flex" for i in range(6)], ) def _docs_app_sections_small_screen(): return rx.el.div( rx.el.div( rx.grid( rx.foreach( features_data, lambda feature: _docs_app_section_features_small_screen(feature), ), class_name="grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-10 w-full", ), class_name="flex flex-col gap-y-4 justify-start py-4", ), ) screen_normalization = "z-[99] w-full" ``` ## Feature Overview Reflex Build provides a streamlined interface for building AI applications. The **Project Menu Bar** helps you manage sessions and stored variables, while the **Chat Area** displays real-time prompts, edits, and file generations. The **Application Workspace** organizes your project structure, and the **Code Editor** allows direct, instant code editing. Key actions like deploy and share are accessible via the **Bottom Menu Bar**, and the **Preview Tab** lets you view and interact with your live app at any time. ```python eval rx.el.div( _docs_app_sections_small_screen(), ) ``` ## Interface Highlights Reflex Build’s interface is designed for clarity and efficiency. The **Project Menu Bar** helps you manage sessions, apps, and variables. The **Chat Area** shows prompts in action with visual feedback and file generation. In the **Application Workspace**, you can view and organize your project files. The **Code Editor** allows quick, direct edits with instant saving. Use the **Bottom Menu Bar** for key actions like deploy and download. The **Preview Tab** lets you interact with a live version of your app, including refresh and full-screen options. ```python eval rx.el.div( rx.el.div(_docs_features(), class_name=screen_normalization), ) ``` # Python Libraries Source: http://localhost:3000/docs/ai/python-libraries.md Not every service or tool has a first-class integration — but your app can still connect to **any Python library** directly. By leveraging the built-in Python runtime, the AI Builder can install packages, import libraries, and call their functions from workflows or components. This gives you maximum flexibility to extend your app with the broader Python ecosystem. When you ask for a certain functionality the AI Builder will first check if there is a `first-class integration` available. If not, it will `search the web` to try and find a relevant Python library to fulfill your request. If it finds one, it will install the package and ask you to set any `API keys` that are required. ## Example Use Cases ### Slack There is no built-in integration for Slack. But if you ask the AI Builder to send a message to a Slack channel, it will research itself the best implementation and then use the `slack_sdk` Python package to send the message. ### Scikit-learn There is no built-in integration for Scikit-learn. But if you ask the AI Builder to classify some text using scikit-learn, it will research itself the best implementation and then use the `scikit-learn` Python package to load a pre-trained model and classify the text. ## Adding Custom Knowledge If you are working with a specialized / less well-known library, you can add custom knowledge to help the AI Builder understand how to use it. Simply provide a brief description of the library, its purpose, and example usage in the **Knowledge** section of your app settings. This will guide the AI Builder when it attempts to call functions from that library. ```python exec import reflex as rx ``` ```md alert warning # Where to find the Knowledge Section ``` ```python eval rx.image( src="https://web.reflex-assets.dev/ai_builder/features/knowledge_light.avif", alt="Where to find the Knowledge Section", class_name="rounded-lg border border-secondary-a4 mb-2", ) ``` ## What is Not Supported There are a very small number of libraries that are not supported due to their size. For example, large machine learning frameworks like `torch` or `tensorflow` are not supported directly. In these cases, we recommend using a first-class integration that can emulate similar functionality (e.g., the Replicate integration for running ML models in the cloud). # URLs Source: http://localhost:3000/docs/ai/urls.md When you **paste a URL directly into the AI Builder chat**, the AI will automatically decide how to handle it depending on your prompt. You can use URLs to **copy a page’s design** or **extract its content**, without needing to set up any integration. ## How It Works * If you say something like **“copy the design”** or **“use this layout”**, the AI will: * Take a **screenshot** of the page. * Use it as a **visual reference** to recreate the UI in your app. * Allow you to **customize** the generated design afterward. * 🪄 If you say something like **“get the content”**, **“scrape this page”**, or just paste the URL without mentioning design, the AI will: * **Scrape the content** of the page (text, links, images, metadata). * Return it as structured data that can be used in components, workflows, or AI actions. ## Example Prompts * “Copy the design of this page.” * “Scrape the content from this blog post.” * “Get all the product details from this URL.” * (Paste the URL alone) → AI will assume content scraping by default. ## Notes * **Public pages only:** The AI can only process URLs that are publicly accessible. * **Editable:** Both the generated design and scraped content can be modified after processing. # Webhooks Source: http://localhost:3000/docs/ai/webhooks.md Webhooks allow your app to **send data to external services** in real time. You provide the AI Builder with a **webhook URL** created in another platform, and it can **automatically send payloads** to that URL when workflows are triggered. This is a simple and powerful way to integrate with services that support incoming webhooks, even if there’s no first-class integration. ## What You Can Do With outgoing webhooks, your app can: * **Send structured payloads** to any service that supports incoming webhooks (e.g., Slack, Zapier, Make, Discord). * **Trigger external workflows** when events happen in your app. * **Push real-time updates** to third-party systems without writing custom backend code. * Chain webhook calls with other integrations or AI actions. ## Step 1: Create a Webhook in the External Service 1. Go to the external service you want to connect (e.g., Slack, Zapier, Discord, Make). 2. Create a new **incoming webhook** in that service. 3. Copy the **webhook URL** it provides. ## Step 2: Add the Webhook URL to AI Builder 1. In the AI Builder chat paste the **webhook URL** you created in the external service. 2. You can then instruct the AI to **send data to this URL** whenever a workflow is triggered. 3. Optionally define the **payload structure** (e.g., JSON body) and when it should be sent. > 💡 Example: “Send user signup data to this webhook whenever a user signs up.” ## Step 3: Sending Payloads * The AI Builder will write the code to send a `POST` request to the webhook URL with the payload you define. * The payload can include **dynamic data** from your app — such as user info, state variables, or model outputs. * You can trigger these webhook calls from buttons, events, workflows, or automations. ## Step 4: Notes * **Security:** Only use webhook URLs from trusted services — they will receive your data as-is. * **Formatting:** Make sure the payload matches the expected format of the external service. * **Chaining:** You can use multiple webhooks or combine them with other integrations. * **Use cases:** Slack alerts, CRM updates, triggering automations in Zapier or Make, notifying custom systems. # Browser Javascript Source: http://localhost:3000/docs/api-reference/browser-javascript.md ```python exec import asyncio from typing import Any import reflex as rx ``` Reflex compiles your frontend code, defined as python functions, into a Javascript web application that runs in the user's browser. There are instances where you may need to supply custom javascript code to interop with Web APIs, use certain third-party libraries, or wrap low-level functionality that is not exposed via Reflex's Python API. ```md alert # Avoid Custom Javascript Custom Javascript code in your Reflex app presents a maintenance challenge, as it will be harder to debug and may be unstable across Reflex versions. Prefer to use the Python API whenever possible and file an issue if you need additional functionality that is not currently provided. ``` ## Executing Script There are four ways to execute custom Javascript code into your Reflex app: - `rx.script` - Injects the script via `next/script` for efficient loading of inline and external Javascript code. Described further in the [component library](/docs/library/other/script). - These components can be directly included in the body of a page, or they may be passed to `rx.App(head_components=[rx.script(...)])` to be included in the `` tag of all pages. - `rx.call_script` - An event handler that evaluates arbitrary Javascript code, and optionally returns the result to another event handler. These previous two methods can work in tandem to load external scripts and then call functions defined within them in response to user events. The following two methods are geared towards wrapping components and are described with examples in the [Wrapping React](/docs/wrapping-react/overview) section. - `_get_hooks` and `_get_custom_code` in an `rx.Component` subclass - `Var.create` with `_var_is_local=False` ## Inline Scripts The `rx.script` component is the recommended way to load inline Javascript for greater control over frontend behavior. The functions and variables in the script can be accessed from backend event handlers or frontend event triggers via the `rx.call_script` interface. ```python demo exec class SoundEffectState(rx.State): @rx.event(background=True) async def delayed_play(self): await asyncio.sleep(1) return rx.call_script("playFromStart(button_sfx)") def sound_effect_demo(): return rx.hstack( rx.script(""" var button_sfx = new Audio("/vintage-button-sound-effect.mp3") function playFromStart (sfx) {sfx.load(); sfx.play()}"""), rx.button( "Play Immediately", on_click=rx.call_script("playFromStart(button_sfx)") ), rx.button("Play Later", on_click=SoundEffectState.delayed_play), ) ``` ## External Scripts External scripts can be loaded either from the `assets` directory, or from CDN URL, and then controlled via `rx.call_script`. ```python demo rx.vstack( rx.script( src="https://cdn.jsdelivr.net/gh/scottschiller/snowstorm@snowstorm_20131208/snowstorm-min.js", ), rx.script(""" window.addEventListener('load', function() { if (typeof snowStorm !== 'undefined') { snowStorm.autoStart = false; snowStorm.snowColor = '#111'; } }); """), rx.button("Start Duststorm", on_click=rx.call_script("snowStorm.start()")), rx.button("Toggle Duststorm", on_click=rx.call_script("snowStorm.toggleSnow()")), ) ``` ## Accessing Client Side Values The `rx.call_script` function accepts a `callback` parameter that expects an Event Handler with one argument which will receive the result of evaluating the Javascript code. This can be used to access client-side values such as the `window.location` or current scroll location, or any previously defined value. ```python demo exec class WindowState(rx.State): location: dict[str, str] = {} scroll_position: dict[str, int] = {} def update_location(self, location): self.location = location def update_scroll_position(self, scroll_position): self.scroll_position = { "x": scroll_position[0], "y": scroll_position[1], } @rx.event def get_client_values(self): return [ rx.call_script("window.location", callback=WindowState.update_location), rx.call_script( "[window.scrollX, window.scrollY]", callback=WindowState.update_scroll_position, ), ] def window_state_demo(): return rx.vstack( rx.button("Update Values", on_click=WindowState.get_client_values), rx.text(f"Scroll Position: {WindowState.scroll_position.to_string()}"), rx.text("window.location:"), rx.text_area(value=WindowState.location.to_string(), is_read_only=True), on_mount=WindowState.get_client_values, ) ``` ```md alert # Allowed Callback Values The `callback` parameter may be an `EventHandler` with one argument, or a lambda with one argument that returns an `EventHandler`. If the callback is None, then no event is triggered. ``` ## Using React Hooks To use React Hooks directly in a Reflex app, you must subclass `rx.Component`, typically `rx.Fragment` is used when the hook functionality has no visual element. The hook code is returned by the `add_hooks` method, which is expected to return a `list[str]` containing Javascript code which will be inserted into the page component (i.e the render function itself). For supporting code that must be defined outside of the component render function, use `_get_custom_code`. The following example uses `useEffect` to register global hotkeys on the `document` object, and then triggers an event when a specific key is pressed. ```python demo exec import dataclasses from reflex.utils import imports @dataclasses.dataclass class KeyEvent: """Interface of Javascript KeyboardEvent""" key: str = "" def key_event_spec(ev: rx.Var[KeyEvent]) -> tuple[rx.Var[str]]: # Takes the event object and returns the key pressed to send to the state return (ev.key,) class GlobalHotkeyState(rx.State): key: str = "" @rx.event def update_key(self, key): self.key = key class GlobalHotkeyWatcher(rx.Fragment): """A component that listens for key events globally.""" # The event handler that will be called on_key_down: rx.EventHandler[key_event_spec] def add_imports(self) -> imports.ImportDict: """Add the imports for the component.""" return { "react": [imports.ImportVar(tag="useEffect")], } def add_hooks(self) -> list[str | rx.Var]: """Add the hooks for the component.""" return [ """ useEffect(() => { const handle_key = %s; document.addEventListener("keydown", handle_key, false); return () => { document.removeEventListener("keydown", handle_key, false); } }) """ % str(rx.Var.create(self.event_triggers["on_key_down"])) ] def global_key_demo(): return rx.vstack( GlobalHotkeyWatcher.create( keys=["a", "s", "d", "w"], on_key_down=lambda key: rx.cond( rx.Var.create(["a", "s", "d", "w"]).contains(key), GlobalHotkeyState.update_key(key), rx.console_log(key), ), ), rx.text("Press a, s, d or w to trigger an event"), rx.heading(f"Last watched key pressed: {GlobalHotkeyState.key}"), ) ``` This snippet can also be imported through pip: [reflex-global-hotkey](https://pypi.org/project/reflex-global-hotkey/). # Browser Storage Source: http://localhost:3000/docs/api-reference/browser-storage.md ## rx.Cookie Represents a state Var that is stored as a cookie in the browser. Currently only supports string values. Parameters - `name` : The name of the cookie on the client side. - `path`: The cookie path. Use `/` to make the cookie accessible on all pages. - `max_age` : Relative max age of the cookie in seconds from when the client receives it. - `domain`: Domain for the cookie (e.g., `sub.domain.com` or `.allsubdomains.com`). - `secure`: If the cookie is only accessible through HTTPS. - `same_site`: Whether the cookie is sent with third-party requests. Can be one of (`True`, `False`, `None`, `lax`, `strict`). ```python class CookieState(rx.State): c1: str = rx.Cookie() c2: str = rx.Cookie("c2 default") # cookies with custom settings c3: str = rx.Cookie(max_age=2) # expires after 2 second c4: str = rx.Cookie(same_site="strict") c5: str = rx.Cookie(path="/foo/") # only accessible on `/foo/` c6: str = rx.Cookie(name="c6-custom-name") ``` ```md alert warning # **The default value of a Cookie is never set in the browser!** The Cookie value is only set when the Var is assigned. If you need to set a default value, you can assign a value to the cookie in an `on_load` event handler. ``` ## Accessing Cookies Cookies are accessed like any other Var in the state. If another state needs access to the value of a cookie, the state should be a substate of the state that defines the cookie. Alternatively the `get_state` API can be used to access the other state. For rendering cookies in the frontend, import the state that defines the cookie and reference it directly. ```md alert warning # **Two separate states should _avoid_ defining `rx.Cookie` with the same name.** Although it is technically possible, the cookie options may differ, leading to unexpected results. Additionally, updating the cookie value in one state will not automatically update the value in the other state without a page refresh or navigation event. ``` ## rx.remove_cookies Remove a cookie from the client's browser. Parameters: - `key`: The name of cookie to remove. ```python rx.button("Remove cookie", on_click=rx.remove_cookie("key")) ``` This event can also be returned from an event handler: ```python class CookieState(rx.State): ... def logout(self): return rx.remove_cookie("auth_token") ``` ## rx.LocalStorage Represents a state Var that is stored in localStorage in the browser. Currently only supports string values. Parameters - `name`: The name of the storage key on the client side. - `sync`: Boolean indicates if the state should be kept in sync across tabs of the same browser. ```python class LocalStorageState(rx.State): # local storage with default settings l1: str = rx.LocalStorage() # local storage with custom settings l2: str = rx.LocalStorage("l2 default") l3: str = rx.LocalStorage(name="l3") # local storage that automatically updates in other states across tabs l4: str = rx.LocalStorage(sync=True) ``` ### Syncing Vars Because LocalStorage applies to the entire browser, all LocalStorage Vars are automatically shared across tabs. The `sync` parameter controls whether an update in one tab should be actively propagated to other tabs without requiring a navigation or page refresh event. ## rx.remove_local_storage Remove a local storage item from the client's browser. Parameters - `key`: The key to remove from local storage. ```python rx.button( "Remove Local Storage", on_click=rx.remove_local_storage("key"), ) ``` This event can also be returned from an event handler: ```python class LocalStorageState(rx.State): ... def logout(self): return rx.remove_local_storage("local_storage_state.l1") ``` ## rx.clear_local_storage() Clear all local storage items from the client's browser. This may affect other apps running in the same domain or libraries within your app that use local storage. ```python rx.button( "Clear all Local Storage", on_click=rx.clear_local_storage(), ) ``` ## rx.SessionStorage Represents a state Var that is stored in sessionStorage in the browser. Similar to localStorage, but the data is cleared when the page session ends (when the browser/tab is closed). Currently only supports string values. Parameters - `name`: The name of the storage key on the client side. ```python class SessionStorageState(rx.State): # session storage with default settings s1: str = rx.SessionStorage() # session storage with custom settings s2: str = rx.SessionStorage("s2 default") s3: str = rx.SessionStorage(name="s3") ``` ### Session Persistence SessionStorage data is cleared when the page session ends. A page session lasts as long as the browser is open and survives page refreshes and restores, but is cleared when the tab or browser is closed. Unlike LocalStorage, SessionStorage is isolated to the tab/window in which it was created, so it's not shared with other tabs/windows of the same origin. ## rx.remove_session_storage Remove a session storage item from the client's browser. Parameters - `key`: The key to remove from session storage. ```python rx.button( "Remove Session Storage", on_click=rx.remove_session_storage("key"), ) ``` This event can also be returned from an event handler: ```python class SessionStorageState(rx.State): ... def logout(self): return rx.remove_session_storage("session_storage_state.s1") ``` ## rx.clear_session_storage() Clear all session storage items from the client's browser. This may affect other apps running in the same domain or libraries within your app that use session storage. ```python rx.button( "Clear all Session Storage", on_click=rx.clear_session_storage(), ) ``` # Serialization Strategies If a non-trivial data structure should be stored in a `Cookie`, `LocalStorage`, or `SessionStorage` var it needs to be serialized before and after storing it. It is recommended to use a pydantic class for the data which provides simple serialization helpers and works recursively in complex object structures. ```python demo exec import reflex as rx import pydantic class AppSettings(pydantic.BaseModel): theme: str = "light" sidebar_visible: bool = True update_frequency: int = 60 error_messages: list[str] = pydantic.Field(default_factory=list) class ComplexLocalStorageState(rx.State): data_raw: str = rx.LocalStorage("{}") data: AppSettings = AppSettings() settings_open: bool = False @rx.event def save_settings(self): self.data_raw = self.data.model_dump_json() self.settings_open = False @rx.event def open_settings(self): self.data = AppSettings.model_validate_json(self.data_raw) self.settings_open = True @rx.event def set_field(self, field, value): setattr(self.data, field, value) def app_settings(): return rx.form.root( rx.foreach( ComplexLocalStorageState.data.error_messages, rx.text, ), rx.form.field( rx.flex( rx.form.label( "Theme", rx.input( value=ComplexLocalStorageState.data.theme, on_change=lambda v: ComplexLocalStorageState.set_field( "theme", v ), ), ), rx.form.label( "Sidebar Visible", rx.switch( checked=ComplexLocalStorageState.data.sidebar_visible, on_change=lambda v: ComplexLocalStorageState.set_field( "sidebar_visible", v, ), ), ), rx.form.label( "Update Frequency (seconds)", rx.input( value=ComplexLocalStorageState.data.update_frequency, on_change=lambda v: ComplexLocalStorageState.set_field( "update_frequency", v, ), ), ), rx.dialog.close(rx.button("Save", type="submit")), gap=2, direction="column", ) ), on_submit=lambda _: ComplexLocalStorageState.save_settings(), ) def app_settings_example(): return rx.dialog.root( rx.dialog.trigger( rx.button("App Settings", on_click=ComplexLocalStorageState.open_settings), ), rx.dialog.content( rx.dialog.title("App Settings"), app_settings(), ), ) ``` # Comparison of Storage Types Here's a comparison of the different client-side storage options in Reflex: | Feature | rx.Cookie | rx.LocalStorage | rx.SessionStorage | | ------------------- | --------------------------------- | --------------------------- | --------------------------- | | Persistence | Until cookie expires | Until explicitly deleted | Until browser/tab is closed | | Storage Limit | ~4KB | ~5MB | ~5MB | | Sent with Requests | Yes | No | No | | Accessibility | Server & Client | Client Only | Client Only | | Expiration | Configurable | Never | End of session | | Scope | Configurable (domain, path) | Origin (domain) | Tab/Window | | Syncing Across Tabs | No | Yes (with sync=True) | No | | Use Case | Authentication, Server-side state | User preferences, App state | Temporary session data | # When to Use Each Storage Type ## Use rx.Cookie When: - You need the data to be accessible on the server side (cookies are sent with HTTP requests) - You're handling user authentication - You need fine-grained control over expiration and scope - You need to limit the data to specific paths in your app ## Use rx.LocalStorage When: - You need to store larger amounts of data (up to ~5MB) - You want the data to persist indefinitely (until explicitly deleted) - You need to share data between different tabs/windows of your app - You want to store user preferences that should be remembered across browser sessions ## Use rx.SessionStorage When: - You need temporary data that should be cleared when the browser/tab is closed - You want to isolate data to a specific tab/window - You're storing sensitive information that shouldn't persist after the session ends - You're implementing per-session features like form data, shopping carts, or multi-step processes - You want to persist data for a state after Redis expiration (for server-side state that needs to survive longer than Redis TTL) # CLI Source: http://localhost:3000/docs/api-reference/cli.md The `reflex` command line interface (CLI) is a tool for creating and managing Reflex apps. To see a list of all available commands, run `reflex --help`. ```bash $ reflex --help Usage: reflex [OPTIONS] COMMAND [ARGS]... Reflex CLI to create, run, and deploy apps. Options: --version Show the version and exit. --help Show this message and exit. Commands: cloud The Hosting CLI. component CLI for creating custom components. db Subcommands for managing the database schema. deploy Deploy the app to the Reflex hosting service. export Export the app to a zip file. init Initialize a new Reflex app in the current directory. login Authenticate with experimental Reflex hosting service. logout Log out of access to Reflex hosting service. rename Rename the app in the current directory. run Run the app in the current directory. script Subcommands for running helper scripts. ``` ## Init The `reflex init` command creates a new Reflex app in the current directory. If an `rxconfig.py` file already exists already, it will re-initialize the app with the latest template. ```bash $ reflex init --help Usage: reflex init [OPTIONS] Initialize a new Reflex app in the current directory. Options: --name APP_NAME The name of the app to initialize. --template [demo|sidebar|blank] The template to initialize the app with. --loglevel [debug|info|warning|error|critical] The log level to use. [default: LogLevel.INFO] --help Show this message and exit. ``` ## Run The `reflex run` command runs the app in the current directory. By default it runs your app in development mode. This means that the app will automatically reload when you make changes to the code. You can also run in production mode which will create an optimized build of your app. You can configure the mode, as well as other options through flags. ```bash $ reflex run --help Usage: reflex run [OPTIONS] Run the app in the current directory. Options: --env [dev|prod] The environment to run the app in. [default: Env.DEV] --frontend-only Execute only frontend. --backend-only Execute only backend. --frontend-port TEXT Specify a different frontend port. [default: 3000] --backend-port TEXT Specify a different backend port. [default: 8000] --backend-host TEXT Specify the backend host. [default: 0.0.0.0] --loglevel [debug|info|warning|error|critical] The log level to use. [default: LogLevel.INFO] --help Show this message and exit. ``` ## Export You can export your app's frontend and backend to zip files using the `reflex export` command. The frontend is a compiled NextJS app, which can be deployed to a static hosting service like Github Pages or Vercel. However this is just a static build, so you will need to deploy the backend separately. See the self-hosting guide for more information. ## Rename The `reflex rename` command allows you to rename your Reflex app. This updates the app name in the configuration files. ```bash $ reflex rename --help Usage: reflex rename [OPTIONS] NEW_NAME Rename the app in the current directory. Options: --loglevel [debug|default|info|warning|error|critical] The log level to use. --help Show this message and exit. ``` ## Cloud The `reflex cloud` command provides access to the Reflex Cloud hosting service. It includes subcommands for managing apps, projects, secrets, and more. For detailed documentation on Reflex Cloud and deployment, see the [Cloud Quick Start Guide](https://reflex.dev/docs/hosting/deploy-quick-start/). ## Script The `reflex script` command provides access to helper scripts for Reflex development. ```bash $ reflex script --help Usage: reflex script [OPTIONS] COMMAND [ARGS]... Subcommands for running helper scripts. Options: --help Show this message and exit. ``` # Event Triggers Source: http://localhost:3000/docs/api-reference/event-triggers.md ```python exec from datetime import datetime import reflex as rx ``` Components can modify the state based on user events such as clicking a button or entering text in a field. These events are triggered by event triggers. Event triggers are component specific and are listed in the documentation for each component. ## Component Lifecycle Events Reflex components have lifecycle events like `on_mount` and `on_unmount` that allow you to execute code at specific points in a component's existence. These events are crucial for initializing data, cleaning up resources, and creating dynamic user interfaces. ### When Lifecycle Events Are Activated - **on_mount**: This event is triggered immediately after a component is rendered and attached to the DOM. It fires: - When a page containing the component is first loaded - When a component is conditionally rendered (appears after being hidden) - When navigating to a page containing the component using internal navigation - It does NOT fire when the page is refreshed or when following external links - **on_unmount**: This event is triggered just before a component is removed from the DOM. It fires: - When navigating away from a page containing the component using internal navigation - When a component is conditionally removed from the DOM (e.g., via a condition that hides it) - It does NOT fire when refreshing the page, closing the browser tab, or following external links ## Page Load Events In addition to component lifecycle events, Reflex also provides page-level events like `on_load` that are triggered when a page loads. The `on_load` event is useful for: - Fetching data when a page first loads - Checking authentication status - Initializing page-specific state - Setting default values for cookies or browser storage You can specify an event handler to run when the page loads using the `on_load` parameter in the `@rx.page` decorator or `app.add_page()` method: ```python class State(rx.State): data: dict = dict() @rx.event def get_data(self): # Fetch data when the page loads self.data = fetch_data() @rx.page(on_load=State.get_data) def index(): return rx.text("Data loaded on page load") ``` This is particularly useful for authentication checks: ```python class State(rx.State): authenticated: bool = False @rx.event def check_auth(self): # Check if user is authenticated self.authenticated = check_auth() if not self.authenticated: return rx.redirect("/login") @rx.page(on_load=State.check_auth) def protected_page(): return rx.text("Protected content") ``` For more details on page load events, see the [page load events documentation](/docs/events/page-load-events). # Event Reference --- ## on_focus The on_focus event handler is called when the element (or some element inside of it) receives focus. For example, it's called when the user clicks on a text input. ```python demo exec class FocusState(rx.State): text: str = "Change Me!" @rx.event def change_text(self, text): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def focus_example(): return rx.input(value=FocusState.text, on_focus=FocusState.change_text) ``` ## on_blur The on_blur event handler is called when focus has left the element (or left some element inside of it). For example, it's called when the user clicks outside of a focused text input. ```python demo exec class BlurState(rx.State): text: str = "Change Me!" @rx.event def change_text(self, text): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def blur_example(): return rx.input(value=BlurState.text, on_blur=BlurState.change_text) ``` ## on_change The on_change event handler is called when the value of an element has changed. For example, it's called when the user types into a text input each keystroke triggers the on change. ```python demo exec class ChangeState(rx.State): checked: bool = False @rx.event def set_checked(self): self.checked = not self.checked def change_example(): return rx.switch(on_change=ChangeState.set_checked) ``` ## on_click The on_click event handler is called when the user clicks on an element. For example, it's called when the user clicks on a button. ```python demo exec class ClickState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def click_example(): return rx.button(ClickState.text, on_click=ClickState.change_text) ``` ## on_context_menu The on_context_menu event handler is called when the user right-clicks on an element. For example, it's called when the user right-clicks on a button. ```python demo exec class ContextState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def context_menu_example(): return rx.button(ContextState.text, on_context_menu=ContextState.change_text) ``` ## on_double_click The on_double_click event handler is called when the user double-clicks on an element. For example, it's called when the user double-clicks on a button. ```python demo exec class DoubleClickState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def double_click_example(): return rx.button( DoubleClickState.text, on_double_click=DoubleClickState.change_text ) ``` ## on_mount The on_mount event handler is called after the component is rendered on the page. It is similar to a page on_load event, although it does not necessarily fire when navigating between pages. This event is particularly useful for initializing data, making API calls, or setting up component-specific state when a component first appears. ```python demo exec class MountState(rx.State): events: list[str] = [] data: list[dict] = [] loading: bool = False @rx.event def on_mount(self): self.events = self.events[-4:] + ["on_mount @ " + str(datetime.now())] @rx.event async def load_data(self): self.loading = True yield import asyncio await asyncio.sleep(1) self.data = [dict(id=1, name="Item 1"), dict(id=2, name="Item 2")] self.loading = False def mount_example(): return rx.vstack( rx.heading("Component Lifecycle Demo"), rx.foreach(MountState.events, rx.text), rx.cond( MountState.loading, rx.spinner(), rx.foreach( MountState.data, lambda item: rx.text(f"ID: {item['id']} - {item['name']}"), ), ), on_mount=MountState.on_mount, ) ``` ## on_unmount The on_unmount event handler is called after removing the component from the page. However, on_unmount will only be called for internal navigation, not when following external links or refreshing the page. This event is useful for cleaning up resources, saving state, or performing cleanup operations before a component is removed from the DOM. ```python demo exec class UnmountState(rx.State): events: list[str] = [] resource_id: str = "resource-12345" status: str = "Resource active" @rx.event def on_unmount(self): self.events = self.events[-4:] + ["on_unmount @ " + str(datetime.now())] self.status = f"Resource {self.resource_id} cleaned up" @rx.event def initialize_resource(self): self.status = f"Resource {self.resource_id} initialized" def unmount_example(): return rx.vstack( rx.heading("Unmount Demo"), rx.foreach(UnmountState.events, rx.text), rx.text(UnmountState.status), rx.link( rx.button("Navigate Away (Triggers Unmount)"), href="/", ), on_mount=UnmountState.initialize_resource, on_unmount=UnmountState.on_unmount, ) ``` ## on_mouse_up The on_mouse_up event handler is called when the user releases a mouse button on an element. For example, it's called when the user releases the left mouse button on a button. ```python demo exec class MouseUpState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def mouse_up_example(): return rx.button(MouseUpState.text, on_mouse_up=MouseUpState.change_text) ``` ## on_mouse_down The on_mouse_down event handler is called when the user presses a mouse button on an element. For example, it's called when the user presses the left mouse button on a button. ```python demo exec class MouseDownState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def mouse_down_example(): return rx.button(MouseDownState.text, on_mouse_down=MouseDownState.change_text) ``` ## on_mouse_enter The on_mouse_enter event handler is called when the user's mouse enters an element. For example, it's called when the user's mouse enters a button. ```python demo exec class MouseEnterState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def mouse_enter_example(): return rx.button(MouseEnterState.text, on_mouse_enter=MouseEnterState.change_text) ``` ## on_mouse_leave The on_mouse_leave event handler is called when the user's mouse leaves an element. For example, it's called when the user's mouse leaves a button. ```python demo exec class MouseLeaveState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def mouse_leave_example(): return rx.button(MouseLeaveState.text, on_mouse_leave=MouseLeaveState.change_text) ``` ## on_mouse_move The on_mouse_move event handler is called when the user moves the mouse over an element. For example, it's called when the user moves the mouse over a button. ```python demo exec class MouseMoveState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def mouse_move_example(): return rx.button(MouseMoveState.text, on_mouse_move=MouseMoveState.change_text) ``` ## on_mouse_out The on_mouse_out event handler is called when the user's mouse leaves an element. For example, it's called when the user's mouse leaves a button. ```python demo exec class MouseOutState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def mouse_out_example(): return rx.button(MouseOutState.text, on_mouse_out=MouseOutState.change_text) ``` ## on_mouse_over The on_mouse_over event handler is called when the user's mouse enters an element. For example, it's called when the user's mouse enters a button. ```python demo exec class MouseOverState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def mouse_over_example(): return rx.button(MouseOverState.text, on_mouse_over=MouseOverState.change_text) ``` ## on_scroll The on_scroll event handler is called when the user scrolls the page. For example, it's called when the user scrolls the page down. ```python demo exec class ScrollState(rx.State): text: str = "Change Me!" @rx.event def change_text(self): if self.text == "Change Me!": self.text = "Changed!" else: self.text = "Change Me!" def scroll_example(): return rx.vstack( rx.text("Scroll to make the text below change."), rx.text(ScrollState.text), rx.text("Scroll to make the text above change."), on_scroll=ScrollState.change_text, overflow="auto", height="3em", width="100%", ) ``` # Plugins Source: http://localhost:3000/docs/api-reference/plugins.md ```python exec import reflex as rx ``` Reflex supports a plugin system that allows you to extend the framework's functionality during the compilation process. Plugins can add frontend dependencies, modify build configurations, generate static assets, and perform custom tasks before compilation. ## Configuring Plugins Plugins are configured in your `rxconfig.py` file using the `plugins` parameter: ```python import reflex as rx config = rx.Config( app_name="my_app", plugins=[ rx.plugins.SitemapPlugin(), rx.plugins.TailwindV4Plugin(), ], ) ``` ## Built-in Plugins Reflex comes with several built-in plugins that provide common functionality. ### SitemapPlugin The `SitemapPlugin` automatically generates a sitemap.xml file for your application, which helps search engines discover and index your pages. ```python import reflex as rx config = rx.Config( app_name="my_app", plugins=[ rx.plugins.SitemapPlugin(), ], ) ``` The sitemap plugin automatically includes all your app's routes. For dynamic routes or custom configuration, you can add sitemap metadata to individual pages: ```python @rx.page( route="/blog/[slug]", context={"sitemap": {"changefreq": "weekly", "priority": 0.8}} ) def blog_post(): return rx.text("Blog post content") @rx.page( route="/about", context={"sitemap": {"changefreq": "monthly", "priority": 0.5}} ) def about(): return rx.text("About page") ``` The sitemap configuration supports the following options: - `loc`: Custom URL for the page (required for dynamic routes) - `lastmod`: Last modification date (datetime object) - `changefreq`: How frequently the page changes (`"always"`, `"hourly"`, `"daily"`, `"weekly"`, `"monthly"`, `"yearly"`, `"never"`) - `priority`: Priority of this URL relative to other URLs (0.0 to 1.0) ### TailwindV4Plugin The `TailwindV4Plugin` provides support for Tailwind CSS v4, which is the recommended version for new projects and includes performance improvements and new features. ```python import reflex as rx # Basic configuration config = rx.Config( app_name="my_app", plugins=[ rx.plugins.TailwindV4Plugin(), ], ) ``` You can customize the Tailwind configuration by passing a config dictionary: ```python import reflex as rx tailwind_config = { "theme": { "extend": { "colors": { "brand": { "50": "#eff6ff", "500": "#3b82f6", "900": "#1e3a8a", } } } }, "plugins": ["@tailwindcss/typography"], } config = rx.Config( app_name="my_app", plugins=[ rx.plugins.TailwindV4Plugin(tailwind_config), ], ) ``` ### TailwindV3Plugin The `TailwindV3Plugin` integrates Tailwind CSS v3 into your Reflex application. While still supported, TailwindV4Plugin is recommended for new projects. ```python import reflex as rx # Basic configuration config = rx.Config( app_name="my_app", plugins=[ rx.plugins.TailwindV3Plugin(), ], ) ``` You can customize the Tailwind configuration by passing a config dictionary: ```python import reflex as rx tailwind_config = { "theme": { "extend": { "colors": { "primary": "#3b82f6", "secondary": "#64748b", } } }, "plugins": ["@tailwindcss/typography", "@tailwindcss/forms"], } config = rx.Config( app_name="my_app", plugins=[ rx.plugins.TailwindV3Plugin(tailwind_config), ], ) ``` ## Plugin Management ### Default Plugins Some plugins are enabled by default. Currently, the `SitemapPlugin` is enabled automatically. If you want to disable a default plugin, use the `disable_plugins` parameter: ```python import reflex as rx config = rx.Config( app_name="my_app", disable_plugins=["reflex.plugins.sitemap.SitemapPlugin"], ) ``` ### Plugin Order Plugins are executed in the order they appear in the `plugins` list. This can be important if plugins have dependencies on each other or modify the same files. ```python import reflex as rx config = rx.Config( app_name="my_app", plugins=[ rx.plugins.TailwindV4Plugin(), # Runs first rx.plugins.SitemapPlugin(), # Runs second ], ) ``` ## Plugin Architecture All plugins inherit from the base `Plugin` class and can implement several lifecycle methods: ```python class Plugin: def get_frontend_development_dependencies(self, **context) -> list[str]: """Get NPM packages required by the plugin for development.""" return [] def get_frontend_dependencies(self, **context) -> list[str]: """Get NPM packages required by the plugin.""" return [] def get_static_assets(self, **context) -> Sequence[tuple[Path, str | bytes]]: """Get static assets required by the plugin.""" return [] def get_stylesheet_paths(self, **context) -> Sequence[str]: """Get paths to stylesheets required by the plugin.""" return [] def pre_compile(self, **context) -> None: """Called before compilation to perform custom tasks.""" pass ``` ### Creating Custom Plugins You can create custom plugins by inheriting from the base `Plugin` class: ```python from reflex.plugins.base import Plugin from pathlib import Path class CustomPlugin(Plugin): def get_frontend_dependencies(self, **context): return ["my-custom-package@1.0.0"] def pre_compile(self, **context): # Custom logic before compilation print("Running custom plugin logic...") # Add a custom task context["add_save_task"](self.create_custom_file) def create_custom_file(self): return "public/custom.txt", "Custom content" ``` Then use it in your configuration: ```python import reflex as rx from my_plugins import CustomPlugin config = rx.Config( app_name="my_app", plugins=[ CustomPlugin(), ], ) ``` # Special Events Source: http://localhost:3000/docs/api-reference/special-events.md ```python exec import reflex as rx ``` Reflex includes a set of built-in special events that can be utilized as event triggers or returned from event handlers in your applications. These events enhance interactivity and user experience. Below are the special events available in Reflex, along with explanations of their functionality: ## rx.console_log Perform a console.log in the browser's console. ```python demo rx.button("Log", on_click=rx.console_log("Hello World!")) ``` When triggered, this event logs a specified message to the browser's developer console. It's useful for debugging and monitoring the behavior of your application. ## rx.scroll_to scroll to an element in the page ```python demo rx.button("Scroll to download button", on_click=rx.scroll_to("download button")) ``` When this is triggered, it scrolls to an element passed by id as parameter. Click on button to scroll to download button (rx.download section) at the bottom of the page ## rx.redirect Redirect the user to a new path within the application. ### Parameters - `path`: The destination path or URL to which the user should be redirected. - `external`: If set to True, the redirection will open in a new tab. Defaults to `False`. ```python demo rx.vstack( rx.button( "open in tab", on_click=rx.redirect("/docs/api-reference/special-events") ), rx.button( "open in new tab", on_click=rx.redirect("https://github.com/reflex-dev/reflex/", is_external=True), ), ) ``` When this event is triggered, it navigates the user to a different page or location within your Reflex application. By default, the redirection occurs in the same tab. However, if you set the external parameter to True, the redirection will open in a new tab or window, providing a seamless user experience. This event can also be run from an event handler in State. It is necessary to `return` the `rx.redirect()`. ```python demo exec class RedirectExampleState(rx.State): """The app state.""" @rx.event def change_page(self): return rx.redirect("https://github.com/reflex-dev/reflex/", is_external=True) def redirect_example(): return rx.vstack( rx.button("Change page in State", on_click=RedirectExampleState.change_page), ) ``` ## rx.set_clipboard Set the specified text content to the clipboard. ```python demo rx.button( 'Copy "Hello World" to clipboard', on_click=rx.set_clipboard("Hello World"), ) ``` This event allows you to copy a given text or content to the user's clipboard. It's handy when you want to provide a "Copy to Clipboard" feature in your application, allowing users to easily copy information to paste elsewhere. ## rx.set_value Set the value of a specified reference element. ```python demo rx.hstack( rx.input(id="input1"), rx.button("Erase", on_click=rx.set_value("input1", "")), ) ``` With this event, you can modify the value of a particular HTML element, typically an input field or another form element. ## rx.window_alert Create a window alert in the browser. ```python demo rx.button("Alert", on_click=rx.window_alert("Hello World!")) ``` ## rx.download Download a file at a given path. Parameters: - `url`: The URL of the file to be downloaded. - `data`: The data to be downloaded. Should be `str` or `bytes`, `data:` URI, `PIL.Image`, or any state Var (to be converted to JSON). - `filename`: The desired filename of the downloaded file. ```md alert # `url` and `data` args are mutually exclusive, and at least one of them must be provided. ``` ```python demo rx.button( "Download", on_click=rx.download( url="/reflex_banner.webp", filename="different_name_logo.webp" ), id="download button", ) ``` # Utility Functions Source: http://localhost:3000/docs/api-reference/utils.md ```python exec import reflex as rx ``` Reflex provides utility functions to help with common tasks in your applications. ## run_in_thread The `run_in_thread` function allows you to run a **non-async** function in a separate thread, which is useful for preventing long-running operations from blocking the UI event queue. ```python async def run_in_thread(func: Callable) -> Any ``` ### Parameters - `func`: The non-async function to run in a separate thread. ### Returns - The return value of the function. ### Raises - `ValueError`: If the function is an async function. ### Usage ```python demo exec id=run_in_thread_demo import asyncio import dataclasses import time import reflex as rx def quick_blocking_function(): time.sleep(0.5) return "Quick task completed successfully!" def slow_blocking_function(): time.sleep(3.0) return "This should never be returned due to timeout!" @dataclasses.dataclass class TaskInfo: result: str = "No result yet" status: str = "Idle" class RunInThreadState(rx.State): tasks: list[TaskInfo] = [] @rx.event(background=True) async def run_quick_task(self): """Run a quick task that completes within the timeout.""" async with self: task_ix = len(self.tasks) self.tasks.append(TaskInfo(status="Running quick task...")) task_info = self.tasks[task_ix] try: result = await rx.run_in_thread(quick_blocking_function) async with self: task_info.result = result task_info.status = "Complete" except Exception as e: async with self: task_info.result = f"Error: {str(e)}" task_info.status = "Failed" @rx.event(background=True) async def run_slow_task(self): """Run a slow task that exceeds the timeout.""" async with self: task_ix = len(self.tasks) self.tasks.append(TaskInfo(status="Running slow task...")) task_info = self.tasks[task_ix] try: # Run with a timeout of 1 second (not enough time) result = await asyncio.wait_for( rx.run_in_thread(slow_blocking_function), timeout=1.0, ) async with self: task_info.result = result task_info.status = "Complete" except asyncio.TimeoutError: async with self: # Warning: even though we stopped waiting for the task, # it may still be running in thread task_info.result = "Task timed out after 1 second!" task_info.status = "Timeout" except Exception as e: async with self: task_info.result = f"Error: {str(e)}" task_info.status = "Failed" def run_in_thread_example(): return rx.vstack( rx.heading("run_in_thread Example", size="3"), rx.hstack( rx.button( "Run Quick Task", on_click=RunInThreadState.run_quick_task, color_scheme="green", ), rx.button( "Run Slow Task (exceeds timeout)", on_click=RunInThreadState.run_slow_task, color_scheme="red", ), ), rx.vstack( rx.foreach( RunInThreadState.tasks.reverse()[:10], lambda task: rx.hstack( rx.text(task.status), rx.spacer(), rx.text(task.result), ), ), align="start", width="100%", ), width="100%", align_items="start", spacing="4", ) ``` ### When to Use run_in_thread Use `run_in_thread` when you need to: 1. Execute CPU-bound operations that would otherwise block the event loop 2. Call synchronous libraries that don't have async equivalents 3. Prevent long-running operations from blocking UI responsiveness ### Example: Processing a Large File ```python import reflex as rx import time class FileProcessingState(rx.State): progress: str = "Ready" @rx.event(background=True) async def process_large_file(self): async with self: self.progress = "Processing file..." def process_file(): # Simulate processing a large file time.sleep(5) return "File processed successfully!" # Save the result to a local variable to avoid blocking the event loop. result = await rx.run_in_thread(process_file) async with self: # Then assign the local result to the state while holding the lock. self.progress = result ``` # Reflex's Var System Source: http://localhost:3000/docs/api-reference/var-system.md ## Motivation Reflex supports some basic operations in state variables on the frontend. Reflex automatically converts variable operations from Python into a JavaScript equivalent. Here's an example of a Reflex conditional in Python that returns "Pass" if the threshold is equal to or greater than 50 and "Fail" otherwise: ```py rx.cond( State.threshold >= 50, "Pass", "Fail", ) ``` The conditional to roughly the following in Javascript: ```js state.threshold >= 50 ? "Pass" : "Fail"; ``` ## Overview Simply put, a `Var` in Reflex represents a Javascript expression. If the type is known, it can be any of the following: - `NumberVar` represents an expression that evaluates to a Javascript `number`. `NumberVar` can support both integers and floating point values - `BooleanVar` represents a boolean expression. For example: `false`, `3 > 2`. - `StringVar` represents an expression that evaluates to a string. For example: `'hello'`, `(2).toString()`. - `ArrayVar` represents an expression that evaluates to an array object. For example: `[1, 2, 3]`, `'words'.split()`. - `ObjectVar` represents an expression that evaluates to an object. For example: `{a: 2, b: 3}`, `{deeply: {nested: {value: false}}}`. - `NoneVar` represent null values. These can be either `undefined` or `null`. ## Creating Vars State fields are converted to `Var` by default. Additionally, you can create a `Var` from Python values using `rx.Var.create()`: ```py rx.Var.create(4) # NumberVar rx.Var.create("hello") # StringVar rx.Var.create([1, 2, 3]) # ArrayVar ``` If you want to explicitly create a `Var` from a raw Javascript string, you can instantiate `rx.Var` directly: ```py rx.Var("2", _var_type=int).guess_type() # NumberVar ``` In the example above, `.guess_type()` will attempt to downcast from a generic `Var` type into `NumberVar`. For this example, calling the function `.to(int)` can also be used in place of `.guess_type()`. ## Operations The `Var` system also supports some other basic operations. For example, `NumberVar` supports basic arithmetic operations like `+` and `-`, as in Python. It also supports comparisons that return a `BooleanVar`. Custom `Var` operations can also be defined: ```py from reflex.vars import var_operation, var_operation_return, ArrayVar, NumberVar @var_operation def multiply_array_values(a: ArrayVar): return var_operation_return( js_expression=f"{a}.reduce((p, c) => p * c, 1)", var_type=int, ) def factorial(value: NumberVar): return rx.cond(value <= 1, 1, multiply_array_values(rx.Var.range(1, value + 1))) ``` Use `js_expression` to pass explicit JavaScript expressions; in the `multiply_array_values` example, we pass in a JavaScript expression that calculates the product of all elements in an array called `a` by using the reduce method to multiply each element with the accumulated result, starting from an initial value of 1. Later, we leverage `rx.cond` in the' factorial' function, we instantiate an array using the `range` function, and pass this array to `multiply_array_values`. # API Routes Overview Source: http://localhost:3000/docs/api-routes/overview.md ```python exec import reflex as rx ``` In addition to your frontend app, Reflex uses a FastAPI backend to serve your app. The API transformer feature allows you to transform or extend the ASGI app that serves your Reflex application. ## Overview The API transformer provides a way to: 1. Integrate existing FastAPI or Starlette applications with your Reflex app 2. Apply middleware or transformations to the ASGI app 3. Extend your Reflex app with additional API endpoints This is useful for creating a backend API that can be used for purposes beyond your Reflex app, or for integrating Reflex with existing backend services. ## Using API Transformer You can set the `api_transformer` parameter when initializing your Reflex app: ```python import reflex as rx from fastapi import FastAPI, Depends from fastapi.security import OAuth2PasswordBearer # Create a FastAPI app fastapi_app = FastAPI(title="My API") # Add routes to the FastAPI app @fastapi_app.get("/api/items") async def get_items(): return dict(items=["Item1", "Item2", "Item3"]) # Create a Reflex app with the FastAPI app as the API transformer app = rx.App(api_transformer=fastapi_app) ``` ## Types of API Transformers The `api_transformer` parameter can accept: 1. A Starlette or FastAPI instance 2. A callable that takes an ASGIApp and returns an ASGIApp 3. A sequence of the above ### Using a FastAPI or Starlette Instance When you provide a FastAPI or Starlette instance as the API transformer, Reflex will mount its internal API to your app, allowing you to define additional routes: ```python import reflex as rx from fastapi import FastAPI, Depends from fastapi.security import OAuth2PasswordBearer # Create a FastAPI app with authentication fastapi_app = FastAPI(title="Secure API") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") # Add a protected route @fastapi_app.get("/api/protected") async def protected_route(token: str = Depends(oauth2_scheme)): return dict(message="This is a protected endpoint") # Create a token endpoint @fastapi_app.post("/token") async def login(username: str, password: str): # In a real app, you would validate credentials if username == "user" and password == "password": return dict(access_token="example_token", token_type="bearer") return dict(error="Invalid credentials") # Create a Reflex app with the FastAPI app as the API transformer app = rx.App(api_transformer=fastapi_app) ``` ### Using a Callable Transformer You can also provide a callable that transforms the ASGI app: ```python import reflex as rx from starlette.middleware.cors import CORSMiddleware # Create a transformer function that returns a transformed ASGI app def add_cors_middleware(app): # Wrap the app with CORS middleware and return the wrapped app return CORSMiddleware( app=app, allow_origins=["https://example.com"], allow_methods=["*"], allow_headers=["*"], ) # Create a Reflex app with the transformer app = rx.App(api_transformer=add_cors_middleware) ``` ### Using Multiple Transformers You can apply multiple transformers by providing a sequence: ```python import reflex as rx from fastapi import FastAPI from starlette.middleware import Middleware from starlette.middleware.cors import CORSMiddleware # Create a FastAPI app fastapi_app = FastAPI(title="My API") # Add routes to the FastAPI app @fastapi_app.get("/api/items") async def get_items(): return dict(items=["Item1", "Item2", "Item3"]) # Create a transformer function def add_logging_middleware(app): # This is a simple example middleware that logs requests async def middleware(scope, receive, send): # Log the request path path = scope["path"] print("Request:", path) await app(scope, receive, send) return middleware # Create a Reflex app with multiple transformers app = rx.App(api_transformer=[fastapi_app, add_logging_middleware]) ``` ## Reserved Routes Some routes on the backend are reserved for the runtime of Reflex, and should not be overridden unless you know what you are doing. ### Ping `localhost:8000/ping/`: You can use this route to check the health of the backend. The expected return is `"pong"`. ### Event `localhost:8000/_event`: the frontend will use this route to notify the backend that an event occurred. ```md alert error # Overriding this route will break the event communication ``` ### Upload `localhost:8000/_upload`: This route is used for file uploads when using `rx.upload()`, including `rx.upload_files(...)` and `rx.upload_files_chunk(...)`. # Assets Source: http://localhost:3000/docs/assets/overview.md ```python exec import reflex as rx ``` Static files such as images and stylesheets can be placed in `assets/` folder of the project. These files can be referenced within your app. ```md alert # Assets are copied during the build process. Any files placed within the `assets/` folder at runtime will not be available to the app when running in production mode. The `assets/` folder should only be used for static files. ``` ## Referencing Assets There are two ways to reference assets in your Reflex app: ### 1. Direct Path Reference To reference an image in the `assets/` folder, pass the relative path as a prop. For example, you can store your logo in your assets folder: ```bash assets └── Reflex.svg ``` Then you can display it using a `rx.image` component: ```python demo rx.image(src="https://web.reflex-assets.dev/other/Reflex.svg", width="5em") ``` ```md alert # Always prefix the asset path with a forward slash `/` to reference the asset from the root of the project, or it may not display correctly on non-root pages. ``` ### 2. Using rx.asset Function The `rx.asset` function provides a more flexible way to reference assets in your app. It supports both local assets (in the app's `assets/` directory) and shared assets (placed next to your Python files). #### Local Assets Local assets are stored in the app's `assets/` directory and are referenced using `rx.asset`: ```python demo rx.image(src=rx.asset("Reflex.svg"), width="5em") ``` #### Shared Assets Shared assets are placed next to your Python file and are linked to the app's external assets directory. This is useful for creating reusable components with their own assets: ```python box # my_component.py import reflex as rx # my_script.js is located in the same directory as this Python file def my_component(): return rx.box( rx.script(src=rx.asset("my_script.js", shared=True)), "Component with custom script", ) ``` You can also specify a subfolder for shared assets: ```python box # my_component.py import reflex as rx # image.png is located in a subfolder next to this Python file def my_component_with_image(): return rx.image(src=rx.asset("image.png", shared=True, subfolder="images")) ``` ```md alert # Shared assets are linked to your app via symlinks. When using `shared=True`, the asset is symlinked from its original location to your app's external assets directory. This allows you to keep assets alongside their related code. ``` ## Favicon The favicon is the small icon that appears in the browser tab. You can add a `favicon.ico` file to the `assets/` folder to change the favicon. # Files Source: http://localhost:3000/docs/assets/upload-and-download-files.md ```python exec import reflex as rx ``` In addition to any assets you ship with your app, many web app will often need to receive or send files, whether you want to share media, allow user to import their data, or export some backend data. In this section, we will cover all you need to know for manipulating files in Reflex. ## Assets vs Upload Directory Before diving into file uploads and downloads, it's important to understand the difference between assets and the upload directory in Reflex: ```python eval # Simple table comparing assets vs upload directory rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Feature"), rx.table.column_header_cell("Assets"), rx.table.column_header_cell("Upload Directory"), ), ), rx.table.body( rx.table.row( rx.table.cell(rx.text("Purpose", font_weight="bold")), rx.table.cell( rx.text( "Static files included with your app (images, stylesheets, scripts)" ) ), rx.table.cell(rx.text("Dynamic files uploaded by users during runtime")), ), rx.table.row( rx.table.cell(rx.text("Location", font_weight="bold")), rx.table.cell( rx.hstack( rx.code( "assets/", style={ "color": rx.color("violet", 11), "border_radius": "0.25rem", "border": f"1px solid {rx.color('violet', 5)}", "background": rx.color("violet", 3), }, ), rx.text(" folder or next to Python files (shared assets)"), spacing="2", ) ), rx.table.cell( rx.hstack( rx.code( "uploaded_files/", style={ "color": rx.color("violet", 11), "border_radius": "0.25rem", "border": f"1px solid {rx.color('violet', 5)}", "background": rx.color("violet", 3), }, ), rx.text(" directory (configurable)"), spacing="2", ) ), ), rx.table.row( rx.table.cell(rx.text("Access Method", font_weight="bold")), rx.table.cell( rx.hstack( rx.code( "rx.asset()", style={ "color": rx.color("violet", 11), "border_radius": "0.25rem", "border": f"1px solid {rx.color('violet', 5)}", "background": rx.color("violet", 3), }, ), rx.text(" or direct path reference"), spacing="2", ) ), rx.table.cell( rx.code( "rx.get_upload_url()", style={ "color": rx.color("violet", 11), "border_radius": "0.25rem", "border": f"1px solid {rx.color('violet', 5)}", "background": rx.color("violet", 3), }, ) ), ), rx.table.row( rx.table.cell(rx.text("When to Use", font_weight="bold")), rx.table.cell( rx.text("For files that are part of your application's codebase") ), rx.table.cell( rx.text( "For files that users upload or generate through your application" ) ), ), rx.table.row( rx.table.cell(rx.text("Availability", font_weight="bold")), rx.table.cell(rx.text("Available at compile time")), rx.table.cell(rx.text("Available at runtime")), ), ), width="100%", ) ``` For more information about assets, see the [Assets Overview](/docs/assets/overview/). ## Download If you want to let the users of your app download files from your server to their computer, Reflex offer you two way. ### With a regular link For some basic usage, simply providing the path to your resource in a `rx.link` will work, and clicking the link will download or display the resource. ```python demo rx.link("Download", href="/reflex_banner.webp") ``` ### With `rx.download` event Using the `rx.download` event will always prompt the browser to download the file, even if it could be displayed in the browser. The `rx.download` event also allows the download to be triggered from another backend event handler. ```python demo rx.button( "Download", on_click=rx.download(url="/reflex_banner.webp"), ) ``` `rx.download` lets you specify a name for the file that will be downloaded, if you want it to be different from the name on the server side. ```python demo rx.button( "Download and Rename", on_click=rx.download(url="/reflex_banner.webp", filename="different_name_logo.png"), ) ``` If the data to download is not already available at a known URL, pass the `data` directly to the `rx.download` event from the backend. ```python demo exec import random class DownloadState(rx.State): @rx.event def download_random_data(self): return rx.download( data=",".join([str(random.randint(0, 100)) for _ in range(10)]), filename="random_numbers.csv", ) def download_random_data_button(): return rx.button( "Download random numbers", on_click=DownloadState.download_random_data ) ``` The `data` arg accepts `str` or `bytes` data, a `data:` URI, `PIL.Image`, or any state Var. If the Var is not already a string, it will be converted to a string using `JSON.stringify`. This allows complex state structures to be offered as JSON downloads. Reference page for `rx.download` [here](/docs/api-reference/special-events#rx.download). ## Upload Uploading files to your server let your users interact with your app in a different way than just filling forms to provide data. The component `rx.upload` let your users upload files on the server. Here is a basic example of how it is used: ```python def index(): return rx.fragment( rx.upload(rx.text("Upload files"), rx.icon(tag="upload")), rx.button(on_submit=State.) ) ``` For detailed information, see the reference page of the component [here](/docs/library/forms/upload). # Authentication Overview Source: http://localhost:3000/docs/authentication/authentication-overview.md Many apps require authentication to manage users. There are a few different ways to accomplish this in Reflex: We have solutions that currently exist outside of the core framework: 1. Local Auth: Uses your own database: https://github.com/masenf/reflex-local-auth 2. Google Auth: Uses sign in with Google: https://github.com/masenf/reflex-google-auth 3. Captcha: Generates tests that humans can pass but automated systems cannot: https://github.com/masenf/reflex-google-recaptcha-v2 4. Magic Link Auth: A passwordless login method that sends a unique, one-time-use URL to a user's email: https://github.com/masenf/reflex-magic-link-auth 5. Clerk Auth: A community member wrapped this component and hooked it up in this app: https://github.com/TimChild/reflex-clerk-api 6. Descope Auth: Enables authentication with Descope, supporting passwordless, social login, SSO, and MFA: https://github.com/descope-sample-apps/reflex-descope-auth If you're using the AI Builder, you can also use the built-in [Authentication Integrations](/docs/ai/integrations/overview) which include Azure Auth, Google Auth, Okta Auth, and Descope. ## Guidance for Implementing Authentication - Store sensitive user tokens and information in [backend-only vars](/docs/vars/base-vars#backend-only-vars). - Validate user session and permissions for each event handler that performs an authenticated action and all computed vars or loader events that access private data. - All content that is statically rendered in the frontend (for example, data hardcoded or loaded at compile time in the UI) will be publicly available, even if the page redirects to a login or uses `rx.cond` to hide content. - Only data that originates from state can be truly private and protected. - When using cookies or local storage, a signed JWT can detect and invalidate any local tampering. More auth documentation on the way. Check back soon! # Client Storage Overview Source: http://localhost:3000/docs/client-storage/overview.md ```python exec import reflex as rx ``` You can use the browser's local storage to persist state between sessions. This allows user preferences, authentication cookies, other bits of information to be stored on the client and accessed from different browser tabs. A client-side storage var looks and acts like a normal `str` var, except the default value is either `rx.Cookie` or `rx.LocalStorage` depending on where the value should be stored. The key name will be based on the var name, but this can be overridden by passing `name="my_custom_name"` as a keyword argument. For more information see [Browser Storage](/docs/api-reference/browser-storage/). Try entering some values in the text boxes below and then load the page in a separate tab or check the storage section of browser devtools to see the values saved in the browser. ```python demo exec class ClientStorageState(rx.State): my_cookie: str = rx.Cookie("") my_local_storage: str = rx.LocalStorage("") custom_cookie: str = rx.Cookie(name="CustomNamedCookie", max_age=3600) @rx.event def set_my_cookie(self, value: str): self.my_cookie = value @rx.event def set_my_local_storage(self, value: str): self.my_local_storage = value @rx.event def set_custom_cookie(self, value: str): self.custom_cookie = value def client_storage_example(): return rx.vstack( rx.hstack( rx.text("my_cookie"), rx.input( value=ClientStorageState.my_cookie, on_change=ClientStorageState.set_my_cookie, ), ), rx.hstack( rx.text("my_local_storage"), rx.input( value=ClientStorageState.my_local_storage, on_change=ClientStorageState.set_my_local_storage, ), ), rx.hstack( rx.text("custom_cookie"), rx.input( value=ClientStorageState.custom_cookie, on_change=ClientStorageState.set_custom_cookie, ), ), ) ``` # Conditional Rendering Source: http://localhost:3000/docs/components/conditional-rendering.md ```python exec import reflex as rx ``` Recall from the [basics](/docs/getting-started/basics) that we cannot use Python `if/else` statements when referencing state vars in Reflex. Instead, use the `rx.cond` component to conditionally render components or set props based on the value of a state var. ```md video https://youtube.com/embed/ITOZkzjtjUA?start=6040&end=6463 # Video: Conditional Rendering ``` ```md alert # Check out the API reference for [cond docs](/docs/library/dynamic-rendering/cond). ``` ```python eval rx.box(height="2em") ``` Below is a simple example showing how to toggle between two text components by checking the value of the state var `show`. ```python demo exec class CondSimpleState(rx.State): show: bool = True @rx.event def change(self): self.show = not (self.show) def cond_simple_example(): return rx.vstack( rx.button("Toggle", on_click=CondSimpleState.change), rx.cond( CondSimpleState.show, rx.text("Text 1", color="blue"), rx.text("Text 2", color="red"), ), ) ``` If `show` is `True` then the first component is rendered (in this case the blue text). Otherwise the second component is rendered (in this case the red text). ## Conditional Props You can also set props conditionally using `rx.cond`. In this example, we set the `color` prop of a text component based on the value of the state var `show`. ```python demo exec class PropCondState(rx.State): value: int @rx.event def set_end(self, value: list[int | float]): self.value = value[0] def cond_prop(): return rx.slider( default_value=[50], on_value_commit=PropCondState.set_end, color_scheme=rx.cond(PropCondState.value > 50, "green", "pink"), width="100%", ) ``` ## Var Operations You can use [var operations](/docs/vars/var-operations) with the `cond` component for more complex conditions. See the full [cond reference](/docs/library/dynamic-rendering/cond) for more details. ## Multiple Conditional Statements The [`rx.match`](/docs/library/dynamic-rendering/match) component in Reflex provides a powerful alternative to`rx.cond` for handling multiple conditional statements and structural pattern matching. This component allows you to handle multiple conditions and their associated components in a cleaner and more readable way compared to nested `rx.cond` structures. ```python demo exec from typing import List import reflex as rx class MatchState(rx.State): cat_breed: str = "" animal_options: List[str] = [ "persian", "siamese", "maine coon", "ragdoll", "pug", "corgi", ] @rx.event def set_cat_breed(self, breed: str): self.cat_breed = breed def match_demo(): return rx.flex( rx.match( MatchState.cat_breed, ("persian", rx.text("Persian cat selected.")), ("siamese", rx.text("Siamese cat selected.")), ( "maine coon", rx.text("Maine Coon cat selected."), ), ("ragdoll", rx.text("Ragdoll cat selected.")), rx.text("Unknown cat breed selected."), ), rx.select( [ "persian", "siamese", "maine coon", "ragdoll", "pug", "corgi", ], value=MatchState.cat_breed, on_change=MatchState.set_cat_breed, ), direction="column", gap="2", ) ``` # Convert HTML to Reflex Source: http://localhost:3000/docs/components/html-to-reflex.md To convert HTML, CSS, or any design into Reflex code, use our AI-powered build tool at [Reflex Build](https://build.reflex.dev). Simply paste your HTML, CSS, or describe what you want to build, and our AI will generate the corresponding Reflex code for you. ## How to use Reflex Build 1. Go to [Reflex Build](https://build.reflex.dev) 2. Paste your HTML/CSS code or describe your design 3. The AI will automatically generate Reflex code 4. Copy the generated code into your Reflex application ## Convert Figma file to Reflex Check out this [Notion doc](https://www.notion.so/reflex-dev/Convert-HTML-to-Reflex-fe22d0641dcd4d5c91c8404ca41c7e77) for a walk through on how to convert a Figma file into Reflex code. # Props Source: http://localhost:3000/docs/components/props.md ```python exec import reflex as rx ``` Props modify the behavior and appearance of a component. They are passed in as keyword arguments to a component. ## Component Props There are props that are shared between all components, but each component can also define its own props. For example, the `rx.image` component has a `src` prop that specifies the URL of the image to display and an `alt` prop that specifies the alternate text for the image. ```python demo rx.image( src="https://web.reflex-assets.dev/other/logo.jpg", alt="Reflex Logo", ) ``` Check the docs for the component you are using to see what props are available and how they affect the component (see the `rx.image` [reference](/docs/library/media/image#api-reference) page for example). ## Common Props Components support many standard HTML properties as props. For example: the HTML [id](https://developer.mozilla.org/en-US/docs/Web/API/Element/id) property is exposed directly as the prop `id`. The HTML [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) property is exposed as the prop `class_name` (note the Pythonic snake_casing!). ```python demo rx.box( "Hello World", id="box-id", class_name=[ "class-name-1", "class-name-2", ], ) ``` In the example above, the `class_name` prop of the `rx.box` component is assigned a list of class names. This means the `rx.box` component will be styled with the CSS classes `class-name-1` and `class-name-2`. ## Style Props In addition to component-specific props, most built-in components support a full range of style props. You can use any [CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties) to style a component. ```python demo rx.button( "Fancy Button", border_radius="1em", box_shadow="rgba(151, 65, 252, 0.8) 0 15px 30px -10px", background_image="linear-gradient(144deg,#AF40FF,#5B42F3 50%,#00DDEB)", box_sizing="border-box", color="white", opacity=1, ) ``` See the [styling docs](/docs/styling/overview) to learn more about customizing the appearance of your app. ## Binding Props to State ```md alert warning # Optional: Learn all about [State](/docs/state/overview) first. ``` Reflex apps define [State](/docs/state/overview) classes that hold variables that can change over time. State may be modified in response to things like user input like clicking a button, or in response to events like loading a page. State vars can be bound to component props, so that the UI always reflects the current state of the app. Try clicking the badge below to change its color. ```python demo exec class PropExampleState(rx.State): text: str = "Hello World" color: str = "red" @rx.event def flip_color(self): if self.color == "red": self.color = "blue" else: self.color = "red" def index(): return rx.button( PropExampleState.text, color_scheme=PropExampleState.color, on_click=PropExampleState.flip_color, ) ``` In this example, the `color_scheme` prop is bound to the `color` state var. When the `flip_color` event handler is called, the `color` var is updated, and the `color_scheme` prop is updated to match. # Rendering Iterables Source: http://localhost:3000/docs/components/rendering-iterables.md ```python exec import reflex as rx ``` Recall again from the [basics](/docs/getting-started/basics) that we cannot use Python `for` loops when referencing state vars in Reflex. Instead, use the `rx.foreach` component to render components from a collection of data. For dynamic content that should automatically scroll to show the newest items, consider using the [auto scroll](/docs/library/dynamic-rendering/auto-scroll) component together with `rx.foreach`. ```python demo exec class IterState(rx.State): color: list[str] = [ "red", "green", "blue", ] def colored_box(color: str): return rx.button(color, background_color=color) def dynamic_buttons(): return rx.vstack( rx.foreach(IterState.color, colored_box), ) ``` Here's the same example using a lambda function. ```python def dynamic_buttons(): return rx.vstack( rx.foreach(IterState.color, lambda color: colored_box(color)), ) ``` You can also use lambda functions directly with components without defining a separate function. ```python def dynamic_buttons(): return rx.vstack( rx.foreach( IterState.color, lambda color: rx.button(color, background_color=color) ), ) ``` In this first simple example we iterate through a `list` of colors and render a dynamic number of buttons. The first argument of the `rx.foreach` function is the state var that you want to iterate through. The second argument is a function that takes in an item from the data and returns a component. In this case, the `colored_box` function takes in a color and returns a button with that color. ## For vs Foreach ```md definition # Regular For Loop - Use when iterating over constants. # Foreach - Use when iterating over state vars. ``` The above example could have been written using a regular Python `for` loop, since the data is constant. ```python demo exec colors = ["red", "green", "blue"] def dynamic_buttons_for(): return rx.vstack( [colored_box(color) for color in colors], ) ``` However, as soon as you need the data to be dynamic, you must use `rx.foreach`. ```python demo exec class DynamicIterState(rx.State): color: list[str] = [ "red", "green", "blue", ] def add_color(self, form_data): self.color.append(form_data["color"]) def dynamic_buttons_foreach(): return rx.vstack( rx.foreach(DynamicIterState.color, colored_box), rx.form( rx.input(name="color", placeholder="Add a color"), rx.button("Add"), on_submit=DynamicIterState.add_color, ), ) ``` ## Render Function The function to render each item can be defined either as a separate function or as a lambda function. In the example below, we define the function `colored_box` separately and pass it to the `rx.foreach` function. ```python demo exec class IterState2(rx.State): color: list[str] = [ "red", "green", "blue", ] def colored_box(color: rx.Var[str]): return rx.button(color, background_color=color) def dynamic_buttons2(): return rx.vstack( rx.foreach(IterState2.color, colored_box), ) ``` Notice that the type annotation for the `color` parameter in the `colored_box` function is `rx.Var[str]` (rather than just `str`). This is because the `rx.foreach` function passes the item as a `Var` object, which is a wrapper around the actual value. This is what allows us to compile the frontend without knowing the actual value of the state var (which is only known at runtime). ## Enumerating Iterables The function can also take an index as a second argument, meaning that we can enumerate through data as shown in the example below. ```python demo exec class IterIndexState(rx.State): color: list[str] = [ "red", "green", "blue", ] def create_button(color: rx.Var[str], index: int): return rx.box( rx.button(f"{index + 1}. {color}"), padding_y="0.5em", ) def enumerate_foreach(): return rx.vstack( rx.foreach(IterIndexState.color, create_button), ) ``` Here's the same example using a lambda function. ```python def enumerate_foreach(): return rx.vstack( rx.foreach( IterIndexState.color, lambda color, index: create_button(color, index) ), ) ``` ## Iterating Dictionaries We can iterate through a `dict` using a `foreach`. When the dict is passed through to the function that renders each item, it is presented as a list of key-value pairs `[("sky", "blue"), ("balloon", "red"), ("grass", "green")]`. ```python demo exec class SimpleDictIterState(rx.State): color_chart: dict[str, str] = { "sky": "blue", "balloon": "red", "grass": "green", } def display_color(color: list): # color is presented as a list key-value pairs [("sky", "blue"), ("balloon", "red"), ("grass", "green")] return rx.box(rx.text(color[0]), bg=color[1], padding_x="1.5em") def dict_foreach(): return rx.grid( rx.foreach( SimpleDictIterState.color_chart, display_color, ), columns="3", ) ``` ```md alert warning # Dict Type Annotation. It is essential to provide the correct full type annotation for the dictionary in the state definition (e.g., `dict[str, str]` instead of `dict`) to ensure `rx.foreach` works as expected. Proper typing allows Reflex to infer and validate the structure of the data during rendering. ``` ## Nested examples `rx.foreach` can be used with nested state vars. Here we use nested `foreach` components to render the nested state vars. The `rx.foreach(project["technologies"], get_badge)` inside of the `project_item` function, renders the `dict` values which are of type `list`. The `rx.box(rx.foreach(NestedStateFE.projects, project_item))` inside of the `projects_example` function renders each `dict` inside of the overall state var `projects`. ```python demo exec class NestedStateFE(rx.State): projects: list[dict[str, list]] = [ { "technologies": [ "Next.js", "Prisma", "Tailwind", "Google Cloud", "Docker", "MySQL", ] }, {"technologies": ["Python", "Flask", "Google Cloud", "Docker"]}, ] def get_badge(technology: rx.Var[str]) -> rx.Component: return rx.badge(technology, variant="soft", color_scheme="green") def project_item(project: rx.Var[dict[str, list]]) -> rx.Component: return rx.box( rx.hstack(rx.foreach(project["technologies"], get_badge)), ) def projects_example() -> rx.Component: return rx.box(rx.foreach(NestedStateFE.projects, project_item)) ``` If you want an example where not all of the values in the dict are the same type then check out the example on [var operations using foreach](/docs/vars/var-operations). Here is a further example of how to use `foreach` with a nested data structure. ```python demo exec class NestedDictIterState(rx.State): color_chart: dict[str, list[str]] = { "purple": ["red", "blue"], "orange": ["yellow", "red"], "green": ["blue", "yellow"], } def display_colors(color: rx.Var[tuple[str, list[str]]]): return rx.vstack( rx.text(color[0], color=color[0]), rx.hstack( rx.foreach( color[1], lambda x: rx.box(rx.text(x, color="black"), bg=x), ) ), ) def nested_dict_foreach(): return rx.grid( rx.foreach( NestedDictIterState.color_chart, display_colors, ), columns="3", ) ``` ## Foreach with Cond We can also use `foreach` with the `cond` component. In this example we define the function `render_item`. This function takes in an `item`, uses the `cond` to check if the item `is_packed`. If it is packed it returns the `item_name` with a `✔` next to it, and if not then it just returns the `item_name`. We use the `foreach` to iterate over all of the items in the `to_do_list` using the `render_item` function. ```python demo exec import dataclasses @dataclasses.dataclass class ToDoListItem: item_name: str is_packed: bool class ForeachCondState(rx.State): to_do_list: list[ToDoListItem] = [ ToDoListItem(item_name="Space suit", is_packed=True), ToDoListItem(item_name="Helmet", is_packed=True), ToDoListItem(item_name="Back Pack", is_packed=False), ] def render_item(item: rx.Var[ToDoListItem]): return rx.cond( item.is_packed, rx.list.item(item.item_name + " ✔"), rx.list.item(item.item_name), ) def packing_list(): return rx.vstack( rx.text("Sammy's Packing List"), rx.list(rx.foreach(ForeachCondState.to_do_list, render_item)), ) ``` # Custom Component CLI Reference Source: http://localhost:3000/docs/custom-components/command-reference.md The custom component commands are under `reflex component` subcommand. To see the list of available commands, run `reflex component --help`. To see the manual on a specific command, run `reflex component --help`, for example, `reflex component init --help`. ```bash reflex component --help ``` ```text Usage: reflex component [OPTIONS] COMMAND [ARGS]... Subcommands for creating and publishing Custom Components. Options: --help Show this message and exit. Commands: init Initialize a custom component. build Build a custom component. share Collect more details on the published package for gallery. ``` ## reflex component init Below is an example of running the `init` command. ```bash reflex component init ``` ```text reflex component init ─────────────────────────────────────── Initializing reflex-google-auth project ─────────────────────────────────────── Info: Populating pyproject.toml with package name: reflex-google-auth Info: Initializing the component directory: custom_components/reflex_google_auth Info: Creating app for testing: google_auth_demo ──────────────────────────────────────────── Initializing google_auth_demo ──────────────────────────────────────────── [07:58:16] Initializing the app directory. console.py:85 Initializing the web directory. console.py:85 Success: Initialized google_auth_demo ─────────────────────────────────── Installing reflex-google-auth in editable mode. ─────────────────────────────────── Info: Package reflex-google-auth installed! Custom component initialized successfully! ─────────────────────────────────────────────────── Project Summary ─────────────────────────────────────────────────── [ README.md ]: Package description. Please add usage examples. [ pyproject.toml ]: Project configuration file. Please fill in details such as your name, email, homepage URL. [ custom_components/ ]: Custom component code template. Start by editing it with your component implementation. [ google_auth_demo/ ]: Demo App. Add more code to this app and test. ``` The `init` command uses the current enclosing folder name to construct a python package name, typically in the kebab case. For example, if running init in folder `google_auth`, the package name will be `reflex-google-auth`. The added prefix reduces the chance of name collision on PyPI (the Python Package Index), and it indicates that the package is a Reflex custom component. The user can override the package name by providing the `--package-name` option. The `init` command creates a set of files and folders prefilled with the package name and other details. During the init, the `custom_component` folder is installed locally in editable mode, so a developer can incrementally develop and test with ease. The changes in component implementation is automatically reflected where it is used. Below is the folder structure after the `init` command. ```text google_auth/ ├── pyproject.toml ├── README.md ├── custom_components/ │ └── reflex_google_auth/ │ ├── google_auth.py │ └── __init__.py └── google_auth_demo/ └── assets/ google_auth_demo/ requirements.txt rxconfig.py ``` ### pyproject.toml The `pyproject.toml` is required for the package to build and be published. It is prefilled with information such as the package name, version (`0.0.1`), author name and email, homepage URL. By default the **Apache-2.0** license is used, the same as Reflex. If any of this information requires update, the user can edit the file by hand. ### README The `README.md` file is created with installation instructions, e.g. `pip install reflex-google-auth`, and a brief description of the package. Typically the `README.md` contains usage examples. On PyPI, the `README.md` is rendered as part of the package page. ### Custom Components Folder The `custom_components` folder is where the actual implementation is. Do not worry about this folder name: there is no need to change it. It is where `pyproject.toml` specifies the source of the python package is. The published package contains the contents inside it, excluding this folder. `reflex_google_auth` is the top folder for importable code. The `reflex_google_auth/__init__.py` imports everything from the `reflex_google_auth/google_auth.py`. For the user of the package, the import looks like `from reflex_google_auth import ABC, XYZ`. `reflex_google_auth/google_auth.py` is prefilled with code example and instructions from the [wrapping react guide](/docs/wrapping-react/overview). ### Demo App Folder A demo app is generated inside `google_auth_demo` folder with import statements and example usage of the component. This is a regular Reflex app. Go into this directory and start using any reflex commands for testing. ### Help Manual The help manual is shown when adding the `--help` option to the command. ```bash reflex component init --help ``` ```text Usage: reflex component init [OPTIONS] Initialize a custom component. Args: library_name: The name of the library. install: Whether to install package from this local custom component in editable mode. loglevel: The log level to use. Raises: Exit: If the pyproject.toml already exists. Options: --library-name TEXT The name of your library. On PyPI, package will be published as `reflex-{library- name}`. --install / --no-install Whether to install package from this local custom component in editable mode. [default: install] --loglevel [debug|info|warning|error|critical] The log level to use. [default: LogLevel.INFO] --help Show this message and exit. ``` ## reflex component publish To publish to a package index, a user is required to already have an account with them. As of **0.7.5**, Reflex does not handle the publishing process for you. You can do so manually by first running `reflex component build` followed by `twine upload` or `uv publish` or your choice of a publishing utility. You can then share your build on our website with `reflex component share`. ## reflex component build It is not required to run the `build` command separately before publishing. The `publish` command will build the package if it is not already built. The `build` command is provided for the user's convenience. The `build` command generates the `.tar.gz` and `.whl` distribution files to be uploaded to the desired package index, for example, PyPI. This command must be run at the top level of the project where the `pyproject.toml` file is. As a result of a successful build, there is a new `dist` folder with the distribution files. ```bash reflex component build --help ``` ```text Usage: reflex component build [OPTIONS] Build a custom component. Must be run from the project root directory where the pyproject.toml is. Args: loglevel: The log level to use. Raises: Exit: If the build fails. Options: --loglevel [debug|info|warning|error|critical] The log level to use. [default: LogLevel.INFO] --help Show this message and exit. ``` # Custom Components Overview Source: http://localhost:3000/docs/custom-components/overview.md ```python exec import reflex as rx ``` Reflex users create many components of their own: ready to use high level components, or nicely wrapped React components. With **Custom Components**, the community can easily share these components now. Release **0.4.3** introduces a series of `reflex component` commands that help developers wrap react components, test, and publish them as python packages. As shown in the image below, there are already a few custom components published on PyPI, such as `reflex-spline`, `reflex-webcam`. Check out the custom components gallery [here](/docs/custom-components/overview). ```python eval rx.center( rx.image( src="https://web.reflex-assets.dev/custom_components/pypi_reflex_custom_components.webp", width="400px", border_radius="15px", border="1px solid", ), ) ``` ## Prerequisites for Publishing In order to publish a Python package, an account is required with a python package index, for example, PyPI. The documentation to create accounts and generate API tokens can be found on their websites. For a quick reference, check out our [Prerequisites for Publishing](/docs/custom-components/prerequisites-for-publishing) page. ## Steps to Publishing Follow these steps to publish the custom component as a python package: 1. `reflex component init`: creates a new custom component project from templates. 2. dev and test: developer implements and tests the custom component. 3. `reflex component build`: builds the package. 4. `twine upload` or `uv publish`: uploads the package to a python package index. ### Initialization ```bash reflex component init ``` First create a new folder for your custom component project, for example `color_picker`. The package name will be `reflex-color-picker`. The prefix `reflex-` is intentionally added for all custom components for easy search on PyPI. If you prefer a particular name for the package, you can either change it manually in the `pyproject.toml` file or add the `--library-name` option in the `reflex component init` command initially. Run `reflex component init`, and a set of files and folders will be created in the `color_picker` folder. The `pyproject.toml` file is the configuration file for the project. The `custom_components` folder is where the custom component implementation is. The `color_picker_demo` folder is a demo Reflex app that uses the custom component. If this is the first time of creating python packages, it is encouraged to browse through all the files (there are not that many) to understand the structure of the project. ```bash color_picker/ ├── pyproject.toml <- Configuration file ├── README.md ├── .gitignore <- Exclude dist/ and metadata folders ├── custom_components/ │ └── reflex_color_picker/ <- Custom component source directory │ ├── color_picker.py │ └── __init__.py └── color_picker_demo/ <- Demo Reflex app directory └── assets/ color_picker_demo/ requirements.txt rxconfig.py ``` ### Develop and Test After finishing the custom component implementation, the user is encouraged to fully test it before publishing. The generated Reflex demo app `color_picker_demo` is a good place to start. It is a regular Reflex app prefilled with imports and usage of this component. During the init, the `custom_component` folder is installed locally in editable mode, so a developer can incrementally develop and test with ease. The changes in component implementation are automatically reflected in the demo app. ### Publish ```bash reflex component build ``` Once you're ready to publish your package, run `reflex component build` to build the package. The command builds the distribution files if they are not already built. The end result is a `dist` folder containing the distribution files. The user does not need to do anything manually with these distribution files. In order to publish these files as a Python package, you need to use a publishing utility. Any would work, but we recommend either [Twine](https://twine.readthedocs.io/en/stable/) or (uv)[https://docs.astral.sh/uv/guides/package/#publishing-your-package]. Make sure to keep your package version in pyproject.toml updated. You can also share your components with the rest of the community at our website using the command `reflex component share`. See you there! # Python Package Index Source: http://localhost:3000/docs/custom-components/prerequisites-for-publishing.md ```python exec import reflex as rx image_style = { "width": "400px", "border_radius": "12px", "border": "1px solid var(--c-slate-5)", } ``` In order to publish a Python package, you need to use a publishing utility. Any would work, but we recommend either [Twine](https://twine.readthedocs.io/en/stable/) or [uv](https://docs.astral.sh/uv/guides/package/#publishing-your-package). ## PyPI It is straightforward to create accounts and API tokens with PyPI. There is official help on the [PyPI website](https://pypi.org/help/). For a quick reference here, go to the top right corner of the PyPI website and look for the button to register and fill out personal information. ```python eval rx.center( rx.image( src="https://web.reflex-assets.dev/custom_components/pypi_register.webp", style=image_style, margin_bottom="16px", loading="lazy", ), ) ``` A user can use username and password to authenticate with PyPI when publishing. ```python eval rx.center( rx.image( src="https://web.reflex-assets.dev/custom_components/pypi_account_settings.webp", style=image_style, margin_bottom="16px", loading="lazy", ), ) ``` Scroll down to the API tokens section and click on the "Add API token" button. Fill out the form and click "Generate API token". ```python eval rx.center( rx.image( src="https://web.reflex-assets.dev/custom_components/pypi_api_tokens.webp", style=image_style, width="700px", loading="lazy", ), ) ``` # Database Overview Source: http://localhost:3000/docs/database/overview.md Reflex uses [sqlmodel](https://sqlmodel.tiangolo.com) to provide a built-in ORM wrapping SQLAlchemy. The examples on this page refer specifically to how Reflex uses various tools to expose an integrated database interface. Only basic use cases will be covered below, but you can refer to the [sqlmodel tutorial](https://sqlmodel.tiangolo.com/tutorial/select/) for more examples and information, just replace `SQLModel` with `rx.Model` and `Session(engine)` with `rx.session()` For advanced use cases, please see the [SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/orm/quickstart.html) (v1.4). ```md alert info # Using NoSQL Databases If you are using a NoSQL database (e.g. MongoDB), you can work with it in Reflex by installing the appropriate Python client library. In this case, Reflex will not provide any ORM features. ``` ## Connecting Reflex provides a built-in SQLite database for storing and retrieving data. You can connect to your own SQL compatible database by modifying the `rxconfig.py` file with your database url. ```python config = rx.Config( app_name="my_app", db_url="sqlite:///reflex.db", ) ``` For more examples of database URLs that can be used, see the [SQLAlchemy docs](https://docs.sqlalchemy.org/en/14/core/engines.html#backend-specific-urls). Be sure to install the appropriate DBAPI driver for the database you intend to use. ## Tables To create a table make a class that inherits from `rx.Model` with and specify that it is a table. ```python class User(rx.Model, table=True): username: str email: str password: str ``` ## Migrations Reflex leverages [alembic](https://alembic.sqlalchemy.org/en/latest/) to manage database schema changes. Before the database feature can be used in a new app you must call `reflex db init` to initialize alembic and create a migration script with the current schema. After making changes to the schema, use `reflex db makemigrations --message 'something changed'` to generate a script in the `alembic/versions` directory that will update the database schema. It is recommended that generated scripts be inspected before applying them. Bear in mind that your newest models will not be detected by the `reflex db makemigrations` command unless imported and used somewhere within the application. The `reflex db migrate` command is used to apply migration scripts to bring the database up to date. During app startup, if Reflex detects that the current database schema is not up to date, a warning will be displayed on the console. ## Queries To query the database you can create a `rx.session()` which handles opening and closing the database connection. You can use normal SQLAlchemy queries to query the database. ```python with rx.session() as session: session.add(User(username="test", email="admin@reflex.dev", password="admin")) session.commit() ``` ```md video https://youtube.com/embed/ITOZkzjtjUA?start=6835&end=8225 # Video: Tutorial of Database Model with Forms, Model Field Changes and Migrations, and adding a DateTime Field ``` # Queries Source: http://localhost:3000/docs/database/queries.md Queries are used to retrieve data from a database. A query is a request for information from a database table or combination of tables. A query can be used to retrieve data from a single table or multiple tables. A query can also be used to insert, update, or delete data from a table. ## Session To execute a query you must first create a `rx.session`. You can use the session to query the database using SQLModel or SQLAlchemy syntax. The `rx.session` statement will automatically close the session when the code block is finished. **If `session.commit()` is not called, the changes will be rolled back and not persisted to the database.** The code can also explicitly rollback without closing the session via `session.rollback()`. The following example shows how to create a session and query the database. First we create a table called `User`. ```python class User(rx.Model, table=True): username: str email: str ``` ### Select Then we create a session and query the User table. ```python class QueryUser(rx.State): name: str users: list[User] @rx.event def get_users(self): with rx.session() as session: self.users = session.exec( User.select().where(User.username.contains(self.name)) ).all() ``` The `get_users` method will query the database for all users that contain the value of the state var `name`. ### Insert Similarly, the `session.add()` method to add a new record to the database or persist an existing object. ```python class AddUser(rx.State): username: str email: str @rx.event def add_user(self): with rx.session() as session: session.add(User(username=self.username, email=self.email)) session.commit() ``` ### Update To update the user, first query the database for the object, make the desired modifications, `.add` the object to the session and finally call `.commit()`. ```python class ChangeEmail(rx.State): username: str email: str @rx.event def modify_user(self): with rx.session() as session: user = session.exec( User.select().where((User.username == self.username)) ).first() user.email = self.email session.add(user) session.commit() ``` ### Delete To delete a user, first query the database for the object, then call `.delete()` on the session and finally call `.commit()`. ```python class RemoveUser(rx.State): username: str @rx.event def delete_user(self): with rx.session() as session: user = session.exec( User.select().where(User.username == self.username) ).first() session.delete(user) session.commit() ``` ## ORM Object Lifecycle The objects returned by queries are bound to the session that created them, and cannot generally be used outside that session. After adding or updating an object, not all fields are automatically updated, so accessing certain attributes may trigger additional queries to refresh the object. To avoid this, the `session.refresh()` method can be used to update the object explicitly and ensure all fields are up to date before exiting the session. ```python class AddUserForm(rx.State): user: User | None = None @rx.event def add_user(self, form_data: dict[str, Any]): with rx.session() as session: self.user = User(**form_data) session.add(self.user) session.commit() session.refresh(self.user) ``` Now the `self.user` object will have a correct reference to the autogenerated primary key, `id`, even though this was not provided when the object was created from the form data. If `self.user` needs to be modified or used in another query in a new session, it must be added to the session. Adding an object to a session does not necessarily create the object, but rather associates it with a session where it may either be created or updated accordingly. ```python class AddUserForm(rx.State): ... @rx.event def update_user(self, form_data: dict[str, Any]): if self.user is None: return with rx.session() as session: self.user.set(**form_data) session.add(self.user) session.commit() session.refresh(self.user) ``` If an ORM object will be referenced and accessed outside of a session, you should call `.refresh()` on it to avoid stale object exceptions. ## Using SQL Directly Avoiding SQL is one of the main benefits of using an ORM, but sometimes it is necessary for particularly complex queries, or when using database-specific features. SQLModel exposes the `session.execute()` method that can be used to execute raw SQL strings. If parameter binding is needed, the query may be wrapped in [`sqlalchemy.text`](https://docs.sqlalchemy.org/en/14/core/sqlelement.html#sqlalchemy.sql.expression.text), which allows colon-prefix names to be used as placeholders. ```md alert info # Never use string formatting to construct SQL queries, as this may lead to SQL injection vulnerabilities in the app. ``` ```python import sqlalchemy import reflex as rx class State(rx.State): @rx.event def insert_user_raw(self, username, email): with rx.session() as session: session.execute( sqlalchemy.text( "INSERT INTO user (username, email) VALUES (:username, :email)" ), {"username": username, "email": email}, ) session.commit() @rx.var def raw_user_tuples(self) -> list[list]: with rx.session() as session: return [list(row) for row in session.execute("SELECT * FROM user").all()] ``` ## Async Database Operations Reflex provides an async version of the session function called `rx.asession` for asynchronous database operations. This is useful when you need to perform database operations in an async context, such as within async event handlers. The `rx.asession` function returns an async SQLAlchemy session that must be used with an async context manager. Most operations against the `asession` must be awaited. ```python import sqlalchemy.ext.asyncio import sqlalchemy import reflex as rx class AsyncUserState(rx.State): users: list[User] = [] @rx.event(background=True) async def get_users_async(self): async with rx.asession() as asession: result = await asession.execute(User.select()) async with self: self.users = result.all() ``` ### Async Select The following example shows how to query the database asynchronously: ```python class AsyncQueryUser(rx.State): name: str users: list[User] = [] @rx.event(background=True) async def get_users(self): async with rx.asession() as asession: stmt = User.select().where(User.username.contains(self.name)) result = await asession.execute(stmt) async with self: self.users = result.all() ``` ### Async Insert To add a new record to the database asynchronously: ```python class AsyncAddUser(rx.State): username: str email: str @rx.event(background=True) async def add_user(self): async with rx.asession() as asession: asession.add(User(username=self.username, email=self.email)) await asession.commit() ``` ### Async Update To update a user asynchronously: ```python class AsyncChangeEmail(rx.State): username: str email: str @rx.event(background=True) async def modify_user(self): async with rx.asession() as asession: stmt = User.select().where(User.username == self.username) result = await asession.execute(stmt) user = result.first() if user: user.email = self.email asession.add(user) await asession.commit() ``` ### Async Delete To delete a user asynchronously: ```python class AsyncRemoveUser(rx.State): username: str @rx.event(background=True) async def delete_user(self): async with rx.asession() as asession: stmt = User.select().where(User.username == self.username) result = await asession.execute(stmt) user = result.first() if user: await asession.delete(user) await asession.commit() ``` ### Async Refresh Similar to the regular session, you can refresh an object to ensure all fields are up to date: ```python class AsyncAddUserForm(rx.State): user: User | None = None @rx.event(background=True) async def add_user(self, form_data: dict[str, str]): async with rx.asession() as asession: async with self: self.user = User(**form_data) asession.add(self.user) await asession.commit() await asession.refresh(self.user) ``` ### Async SQL Execution You can also execute raw SQL asynchronously: ```python class AsyncRawSQL(rx.State): users: list[list] = [] @rx.event(background=True) async def insert_user_raw(self, username, email): async with rx.asession() as asession: await asession.execute( sqlalchemy.text( "INSERT INTO user (username, email) VALUES (:username, :email)" ), dict(username=username, email=email), ) await asession.commit() @rx.event(background=True) async def get_raw_users(self): async with rx.asession() as asession: result = await asession.execute("SELECT * FROM user") async with self: self.users = [list(row) for row in result.all()] ``` ```md alert info # Important Notes for Async Database Operations - Always use the `@rx.event(background=True)` decorator for async event handlers - Most operations against the `asession` must be awaited, including `commit()`, `execute()`, `refresh()`, and `delete()` - The `add()` method does not need to be awaited - Result objects from queries have methods like `all()` and `first()` that are synchronous and return data directly - Use `async with self:` when updating state variables in background tasks ``` # Relationships Source: http://localhost:3000/docs/database/relationships.md Foreign key relationships are used to link two tables together. For example, the `Post` model may have a field, `user_id`, with a foreign key of `user.id`, referencing a `User` model. This would allow us to automatically query the `Post` objects associated with a user, or find the `User` object associated with a `Post`. To establish bidirectional relationships a model must correctly set the `back_populates` keyword argument on the `Relationship` to the relationship attribute in the _other_ model. ## Foreign Key Relationships To create a relationship, first add a field to the model that references the primary key of the related table, then add a `sqlmodel.Relationship` attribute which can be used to access the related objects. Defining relationships like this requires the use of `sqlmodel` objects as seen in the example. ```python from typing import List, Optional import sqlmodel import reflex as rx class Post(rx.Model, table=True): title: str body: str user_id: int = sqlmodel.Field(foreign_key="user.id") user: Optional["User"] = sqlmodel.Relationship(back_populates="posts") flags: Optional[List["Flag"]] = sqlmodel.Relationship(back_populates="post") class User(rx.Model, table=True): username: str email: str posts: List[Post] = sqlmodel.Relationship(back_populates="user") flags: List["Flag"] = sqlmodel.Relationship(back_populates="user") class Flag(rx.Model, table=True): post_id: int = sqlmodel.Field(foreign_key="post.id") user_id: int = sqlmodel.Field(foreign_key="user.id") message: str post: Optional[Post] = sqlmodel.Relationship(back_populates="flags") user: Optional[User] = sqlmodel.Relationship(back_populates="flags") ``` See the [SQLModel Relationship Docs](https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/define-relationships-attributes/) for more details. ## Querying Relationships ### Inserting Linked Objects The following example assumes that the flagging user is stored in the state as a `User` instance and that the post `id` is provided in the data submitted in the form. ```python class FlagPostForm(rx.State): user: User @rx.event def flag_post(self, form_data: dict[str, Any]): with rx.session() as session: post = session.get(Post, int(form_data.pop("post_id"))) flag = Flag(message=form_data.pop("message"), post=post, user=self.user) session.add(flag) session.commit() ``` ### How are Relationships Dereferenced? By default, the relationship attributes are in **lazy loading** or `"select"` mode, which generates a query _on access_ to the relationship attribute. Lazy loading is generally fine for single object lookups and manipulation, but can be inefficient when accessing many linked objects for serialization purposes. There are several alternative loading mechanisms available that can be set on the relationship object or when performing the query. - "joined" or `joinload` - generates a single query to load all related objects at once. - "subquery" or `subqueryload` - generates a single query to load all related objects at once, but uses a subquery to do the join, instead of a join in the main query. - "selectin" or `selectinload` - emits a second (or more) SELECT statement which assembles the primary key identifiers of the parent objects into an IN clause, so that all members of related collections / scalar references are loaded at once by primary key There are also non-loading mechanisms, "raise" and "noload" which are used to specifically avoid loading a relationship. Each loading method comes with tradeoffs and some are better suited for different data access patterns. See [SQLAlchemy: Relationship Loading Techniques](https://docs.sqlalchemy.org/en/14/orm/loading_relationships.html) for more detail. ### Querying Linked Objects To query the `Post` table and include all `User` and `Flag` objects up front, the `.options` interface will be used to specify `selectinload` for the required relationships. Using this method, the linked objects will be available for rendering in frontend code without additional steps. ```python import sqlalchemy class PostState(rx.State): posts: List[Post] @rx.event def load_posts(self): with rx.session() as session: self.posts = session.exec( Post.select.options( sqlalchemy.orm.selectinload(Post.user), sqlalchemy.orm.selectinload(Post.flags).options( sqlalchemy.orm.selectinload(Flag.user), ), ).limit(15) ).all() ``` The loading methods create new query objects and thus may be linked if the relationship itself has other relationships that need to be loaded. In this example, since `Flag` references `User`, the `Flag.user` relationship must be chain loaded from the `Post.flags` relationship. ### Specifying the Loading Mechanism on the Relationship Alternatively, the loading mechanism can be specified on the relationship by passing `sa_relationship_kwargs={"lazy": method}` to `sqlmodel.Relationship`, which will use the given loading mechanism in all queries by default. ```python from typing import List, Optional import sqlmodel import reflex as rx class Post(rx.Model, table=True): ... user: Optional["User"] = sqlmodel.Relationship( back_populates="posts", sa_relationship_kwargs={"lazy": "selectin"}, ) flags: Optional[List["Flag"]] = sqlmodel.Relationship( back_populates="post", sa_relationship_kwargs={"lazy": "selectin"}, ) ``` # Tables Source: http://localhost:3000/docs/database/tables.md Tables are database objects that contain all the data in a database. In tables, data is logically organized in a row-and-column format similar to a spreadsheet. Each row represents a unique record, and each column represents a field in the record. ## Creating a Table To create a table, make a class that inherits from `rx.Model`. The following example shows how to create a table called `User`. ```python class User(rx.Model, table=True): username: str email: str ``` The `table=True` argument tells Reflex to create a table in the database for this class. ### Primary Key By default, Reflex will create a primary key column called `id` for each table. However, if an `rx.Model` defines a different field with `primary_key=True`, then the default `id` field will not be created. A table may also redefine `id` as needed. It is not currently possible to create a table without a primary key. ## Advanced Column Types SQLModel automatically maps basic python types to SQLAlchemy column types, but for more advanced use cases, it is possible to define the column type using `sqlalchemy` directly. For example, we can add a last updated timestamp to the post example as a proper `DateTime` field with timezone. ```python import datetime import sqlmodel import sqlalchemy class Post(rx.Model, table=True): ... update_ts: datetime.datetime = sqlmodel.Field( default=None, sa_column=sqlalchemy.Column( "update_ts", sqlalchemy.DateTime(timezone=True), server_default=sqlalchemy.func.now(), ), ) ``` To make the `Post` model more usable on the frontend, a `dict` method may be provided that converts any fields to a JSON serializable value. In this case, the dict method is overriding the default `datetime` serializer to strip off the microsecond part. ```python class Post(rx.Model, table=True): ... def dict(self, *args, **kwargs) -> dict: d = super().dict(*args, **kwargs) d["update_ts"] = self.update_ts.replace(microsecond=0).isoformat() return d ``` # AG Chart Source: http://localhost:3000/docs/enterprise/ag-chart.md AG Chart is a powerful charting library that provides interactive charts and data visualization components for enterprise applications. ```python demo exec import reflex as rx import reflex_enterprise as rxe def basic_chart(): return rxe.ag_chart( options={ "data": [ {"month": "Jan", "value": 10}, {"month": "Feb", "value": 20}, {"month": "Mar", "value": 15}, ], "series": [ { "type": "line", "xKey": "month", "yKey": "value", } ], }, width="100%", height="400px", ) ``` For more detailed documentation, see the [AG Chart Documentation](https://charts.ag-grid.com/). # Aligned Grids Source: http://localhost:3000/docs/enterprise/ag-grid/aligned-grids.md --- title: Aligned Grids --- AgGrid provides a way to align multiple grids together. This is useful when you want to display related data in a synchronized manner. You can do so through the `aligned_grids` prop. This prop takes a list of grid IDs that you want to align. ```python demo exec import pandas as pd import reflex as rx import reflex_enterprise as rxe # Olympic winners data (originally from https://www.ag-grid.com/example-assets/olympic-winners.json) df = pd.read_json("data/olympic-winners.json") row_data = df.to_dict("records") column_defs = [ {"field": "athlete"}, {"field": "age"}, {"field": "country"}, {"field": "year"}, {"field": "sport"}, { "header_name": "Medals", "children": [ { "field": "total", "column_group_show": "closed", "col_id": "total", "value_getter": "params.data.gold + params.data.silver + params.data.bronze", "width": 100, }, {"field": "gold", "column_group_show": "open", "width": 100}, {"field": "silver", "column_group_show": "open", "width": 100}, {"field": "bronze", "column_group_show": "open", "width": 100}, ], }, ] def aligned_grids_page(): """Aligned grids demo.""" return rx.el.div( rxe.ag_grid( id="grid1", column_defs=column_defs, row_data=row_data, aligned_grids=["grid2"], width="100%", ), rxe.ag_grid( id="grid2", column_defs=column_defs, row_data=row_data, aligned_grids=["grid1"], width="100%", ), class_name="flex flex-col gap-y-6 w-full", ) ``` ```md alert warning # The pivot functionality does not work with aligned grids. This is because pivoting data changes the columns, which would make the aligned grids incompatible, as they are no longer sharing the same set of columns. ``` # Cell Selection Source: http://localhost:3000/docs/enterprise/ag-grid/cell-selection.md --- title: "Cell Selection" order: 8 --- AG Grid provides powerful cell selection capabilities that allow users to select individual cells or ranges of cells. This feature is essential for data manipulation, copying, and advanced interactions like fill handle operations. ## Range Selection To enable cell selection in your AG Grid, set the `cell_selection` prop to `True`. This automatically enables both single cell selection and range selection capabilities. ### Basic Selection Example ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd class CellSelectionState(rx.State): data: list[dict] = [] @rx.event def load_data(self): df = pd.read_json("https://www.ag-grid.com/example-assets/olympic-winners.json") self.data = df.head(10).to_dict("records") @rx.event def echo_selection(self, ranges: list[dict], started: bool, finished: bool): if finished: yield rx.toast(f"Selected ranges: {ranges}") column_defs = [ {"field": "athlete", "width": 150}, {"field": "age", "width": 90}, {"field": "country", "width": 120}, {"field": "year", "width": 90}, {"field": "sport", "width": 120}, {"field": "gold", "width": 100}, {"field": "silver", "width": 100}, {"field": "bronze", "width": 100}, ] def basic_cell_selection(): return rx.vstack( rx.text( "Click and drag to select cells. Selection info will appear in a toast.", size="2", ), rxe.ag_grid( id="basic_cell_selection_grid", column_defs=column_defs, row_data=CellSelectionState.data, cell_selection=True, on_cell_selection_changed=CellSelectionState.echo_selection, width="100%", height="400px", ), on_mount=CellSelectionState.load_data, width="100%", ) ``` ### Advanced Selection Event Handling For more sophisticated selection handling, you can process the selection ranges to calculate detailed information: ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd class AdvancedSelectionState(rx.State): data: list[dict] = [] @rx.event def load_data(self): df = pd.DataFrame({ "name": ["Alice", "Bob", "Charlie", "Diana", "Eve"], "score": [85, 92, 78, 96, 88], "grade": ["B", "A", "C", "A", "B"], "attempts": [3, 2, 4, 1, 3], }) self.data = df.to_dict("records") @rx.event def handle_selection(self, ranges: list[dict], started: bool, finished: bool): if finished and ranges: total_cells = sum( (r.get("endRow", 0) - r.get("startRow", 0) + 1) * len(r.get("columns", [])) for r in ranges ) yield rx.toast(f"Selected {total_cells} cells across {len(ranges)} ranges") editable_column_defs = [ {"field": "name", "width": 120}, {"field": "score", "width": 100, "editable": True}, {"field": "grade", "width": 100, "editable": True}, {"field": "attempts", "width": 120, "editable": True}, ] def advanced_selection_example(): return rx.vstack( rx.text( "Select ranges of cells. Try selecting multiple ranges by holding Ctrl/Cmd.", size="2", ), rxe.ag_grid( id="advanced_selection_grid", column_defs=editable_column_defs, row_data=AdvancedSelectionState.data, cell_selection=True, on_cell_selection_changed=AdvancedSelectionState.handle_selection, width="100%", height="300px", ), on_mount=AdvancedSelectionState.load_data, width="100%", ) ``` ## Fill Handle The fill handle is a powerful feature that allows users to quickly fill cells by dragging from a selected cell or range. When enabled, a small square appears at the bottom-right corner of the selection that users can drag to fill adjacent cells. ### Enabling Fill Handle To enable the fill handle, configure the `cell_selection` prop with a dictionary containing the handle configuration: ```python cell_selection = { "handle": { "mode": "fill", # Enable fill handle } } ``` ### Fill Handle Events When using the fill handle, it will trigger `on_cell_value_changed` for each cell receiving a fill value. This allows your backend to handle the data changes appropriately. ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd class FillHandleState(rx.State): data: list[dict] = [] change_log: list[str] = [] @rx.event def load_data(self): df = pd.DataFrame({ "item": ["Apple", "Banana", "Cherry", "Date", "Elderberry"], "quantity": [10, 15, 8, 12, 20], "price": [1.50, 0.75, 2.00, 3.00, 4.50], "total": [15.00, 11.25, 16.00, 36.00, 90.00], }) self.data = df.to_dict("records") @rx.event def handle_cell_change(self, data: dict): row_index = data.get("rowIndex", 0) field = data.get("colId", "") new_value = data.get("newValue", "") old_value = data.get("oldValue", "") change_msg = f"Row {row_index + 1}, {field}: '{old_value}' → '{new_value}'" self.change_log = [change_msg] + self.change_log[:9] # Keep last 10 changes # Update the data if 0 <= row_index < len(self.data): self.data[row_index][field] = new_value fill_column_defs = [ {"field": "item", "width": 120}, {"field": "quantity", "width": 100, "editable": True, "type": "numericColumn"}, {"field": "price", "width": 100, "editable": True, "type": "numericColumn"}, {"field": "total", "width": 100, "editable": True, "type": "numericColumn"}, ] def fill_handle_example(): return rx.vstack( rx.text( "Select a cell and drag the fill handle (small square at bottom-right) to fill adjacent cells.", size="2", ), rxe.ag_grid( id="fill_handle_grid", column_defs=fill_column_defs, row_data=FillHandleState.data, cell_selection={ "handle": { "mode": "fill", # Enable fill handle } }, on_cell_value_changed=FillHandleState.handle_cell_change, width="100%", height="300px", ), rx.divider(), rx.text("Recent Changes:", weight="bold", size="3"), rx.cond( FillHandleState.change_log, rx.vstack( rx.foreach( FillHandleState.change_log, lambda change: rx.text(change, size="1", color="gray"), ), spacing="1", ), rx.text("No changes yet", size="2", color="gray"), ), on_mount=FillHandleState.load_data, width="100%", spacing="4", ) ``` ## Advanced Configuration Options You can further customize cell selection behavior using additional configuration options: ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd class ConfigurationState(rx.State): data: list[dict] = [] @rx.event def load_data(self): df = pd.DataFrame({ "id": range(1, 8), "name": [ "Product A", "Product B", "Product C", "Product D", "Product E", "Product F", "Product G", ], "category": [ "Electronics", "Clothing", "Electronics", "Books", "Clothing", "Electronics", "Books", ], "price": [299.99, 49.99, 199.99, 24.99, 79.99, 399.99, 19.99], "stock": [15, 32, 8, 45, 23, 12, 67], }) self.data = df.to_dict("records") configuration_column_defs = [ {"field": "id", "width": 80}, {"field": "name", "width": 150, "editable": True}, {"field": "category", "width": 120}, {"field": "price", "width": 100, "editable": True, "type": "numericColumn"}, {"field": "stock", "width": 100, "editable": True, "type": "numericColumn"}, ] def configuration_example(): return rx.vstack( rx.text("Cell selection with additional configuration options", size="2"), rxe.ag_grid( id="configuration_grid", column_defs=configuration_column_defs, row_data=ConfigurationState.data, cell_selection={ "handle": { "mode": "fill", } }, enable_cell_text_selection=True, # Allow text selection within cells suppress_cell_focus=False, # Allow cell focus width="100%", height="350px", ), on_mount=ConfigurationState.load_data, width="100%", ) ``` ## Key Features - **Cell Selection**: Enable with `cell_selection=True` for both single cell and range selection capabilities - **Fill Handle**: Configure with `cell_selection={"handle": {"mode": "fill"}}` for drag-to-fill functionality - **Event Handling**: Use `on_cell_selection_changed` to respond to selection changes - **Value Changes**: Use `on_cell_value_changed` to handle individual cell edits and fill operations - **Text Selection**: Enable `enable_cell_text_selection=True` to allow text selection within cells ## Best Practices 1. **Use cell_selection configuration**: Both single cell and range selection are automatically enabled with `cell_selection=True`, providing all necessary selection capabilities for fill operations. 2. **Handle cell value changes**: When using fill handle, implement `on_cell_value_changed` to process the data updates in your backend. 3. **Provide user feedback**: Use toasts or other UI elements to confirm selection actions and data changes. 4. **Consider performance**: For large datasets, be mindful of the performance impact of frequent cell value change events. 5. **Validate fill operations**: Implement validation logic in your `on_cell_value_changed` handler to ensure data integrity. # Column Definitions Source: http://localhost:3000/docs/enterprise/ag-grid/column-defs.md --- order: 1 --- ## Basic Columns AgGrid allows you to define the columns of your grid, passed to the prop `column_defs`. Each dictionary represents a column. ```md alert warning # If you are converting from other AG Grid implementation, we also support camelCase for the name of the properties. ``` Here we define a grid with 3 columns: ```python column_defs = [ {"field": "direction"}, {"field": "strength"}, {"field": "frequency"}, ] ``` To set default properties for all your columns, you can define `default_col_def` in your grid: ```python default_col_def = { "sortable": True, "filter": True, "resizable": True, } ``` # AG Grid Source: http://localhost:3000/docs/enterprise/ag-grid.md --- title: "AgGrid Overview" order: 3 --- AG Grid is a powerful, feature-rich data grid component that brings enterprise-grade table functionality to your Reflex applications. With support for sorting, filtering, pagination, row selection, and much more, AG Grid transforms how you display and interact with tabular data. [Explore the full AG Grid showcase and examples](https://aggrid.reflex.run/) ## Your First Reflex AG Grid A basic Reflex AG Grid contains column definitions `column_defs`, which define the columns to be displayed in the grid, and `row_data`, which contains the data to be displayed in the grid. Each grid also requires a unique `id`, which is needed to uniquely identify the Ag-Grid instance on the page. If you have multiple grids on the same page, each grid must have a unique `id` so that it can be correctly rendered and managed. ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/wind_dataset.csv") column_defs = [ {"field": "direction"}, {"field": "strength"}, {"field": "frequency"}, ] def ag_grid_simple(): return rxe.ag_grid( id="ag_grid_basic_1", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", ) ``` 📊 **Dataset source:** [wind_dataset.csv](https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv) The format of the data passed to the `row_data` prop is a list of dictionaries. Each dictionary represents a row in the grid as seen below. ```python [ {"direction": "N", "strength": "0-1", "frequency": 0.5}, {"direction": "NNE", "strength": "0-1", "frequency": 0.6}, {"direction": "NE", "strength": "0-1", "frequency": 0.5}, ] ``` The previous example showed the `column_defs` written out in full. You can also extract the required information from the dataframe's column names: ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/wind_dataset.csv") def ag_grid_simple_2(): return rxe.ag_grid( id="ag_grid_basic_2", row_data=df.to_dict("records"), column_defs=[{"field": i} for i in df.columns], width="100%", height="40vh", ) ``` 📊 **Dataset source:** [wind_dataset.csv](https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv) ## Headers In the above example, the first letter of the field names provided are capitalized when displaying the header name. You can customize the header names by providing a `header_name` key in the column definition. In this example, the `header_name` is customized for the second and third columns. ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country"}, {"field": "pop", "headerName": "Population"}, {"field": "lifeExp", "headerName": "Life Expectancy"}, ] def ag_grid_simple_headers(): return rxe.ag_grid( id="ag_grid_basic_headers", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", height="40vh", ) ``` 📊 **Dataset source:** [gapminder2007.csv](https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv) ## Column Filtering Allow a user to filter a column by setting the `filter` key to `True` in the column definition. In this example we enable filtering for the first and last columns. ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country", "headerName": "Country", "filter": True}, {"field": "pop", "headerName": "Population"}, {"field": "lifeExp", "headerName": "Life Expectancy", "filter": True}, ] def ag_grid_simple_column_filtering(): return rxe.ag_grid( id="ag_grid_basic_column_filtering", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", height="40vh", ) ``` ### Filter Types You can set `filter=True` to enable the default filter for a column. You can also set the filter type using the `filter` key. The following filter types are available: `ag_grid.filters.date`, `ag_grid.filters.number` and `ag_grid.filters.text`. These ensure that the input you enter to the filter is of the correct type. (`ag_grid.filters.set` and `ag_grid.filters.multi` are available with AG Grid Enterprise) ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/GanttChart-updated.csv") column_defs = [ {"field": "Task", "filter": True}, {"field": "Start", "filter": rxe.ag_grid.filters.date}, {"field": "Duration", "filter": rxe.ag_grid.filters.number}, {"field": "Resource", "filter": rxe.ag_grid.filters.text}, ] def ag_grid_column_filter_types(): return rxe.ag_grid( id="ag_grid_basic_column_filtering", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", height="40vh", ) ``` 📊 **Dataset source:** [GanttChart-updated.csv](https://raw.githubusercontent.com/plotly/datasets/master/GanttChart-updated.csv) ## Row Sorting By default, the rows can be sorted by any column by clicking on the column header. You can disable sorting of the rows for a column by setting the `sortable` key to `False` in the column definition. In this example, we disable sorting for the first column. ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country", "sortable": False}, {"field": "pop", "headerName": "Population"}, {"field": "lifeExp", "headerName": "Life Expectancy"}, ] def ag_grid_simple_row_sorting(): return rxe.ag_grid( id="ag_grid_basic_row_sorting", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", height="40vh", ) ``` 📊 **Dataset source:** [gapminder2007.csv](https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv) ## Row Selection Row Selection is enabled using the `row_selection` attribute. Setting it to `multiple` allows users to select multiple rows at a time. You can use the `checkbox_selection` column definition attribute to render checkboxes for selection. ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country", "checkboxSelection": True}, {"field": "pop", "headerName": "Population"}, {"field": "continent"}, ] def ag_grid_simple_row_selection(): return rxe.ag_grid( id="ag_grid_basic_row_selection", row_data=df.to_dict("records"), column_defs=column_defs, row_selection={"mode": "multiple"}, width="100%", height="40vh", ) ``` 📊 **Dataset source:** [gapminder2007.csv](https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv) ## Editing Enable Editing by setting the `editable` attribute to `True`. The cell editor is inferred from the cell data type. Set the cell editor type using the `cell_editor` attribute. There are 7 provided cell editors in AG Grid: 1. `ag_grid.editors.text` 2. `ag_grid.editors.large_text` 3. `ag_grid.editors.select` 4. `ag_grid.editors.rich_select` 5. `ag_grid.editors.number` 6. `ag_grid.editors.date` 7. `ag_grid.editors.checkbox` In this example, we enable editing for the second and third columns. The second column uses the `number` cell editor, and the third column uses the `select` cell editor. The `on_cell_value_changed` event trigger is linked to the `cell_value_changed` event handler in the state. This event handler is called whenever a cell value is changed and changes the value of the backend var `_data_df` and the state var `data`. ```python import reflex as rx import reflex_enterprise as rxe import pandas as pd class AGGridEditingState(rx.State): data: list[dict] = [] _data_df: pd.DataFrame @rx.event def load_data(self): self._data_df = pd.read_csv("data/gapminder2007.csv") self.data = self._data_df.to_dict("records") @rx.event def cell_value_changed(self, row, col_field, new_value): self._data_df.at[row, col_field] = new_value self.data = self._data_df.to_dict("records") yield rx.toast( f"Cell value changed, Row: {row}, Column: {col_field}, New Value: {new_value}" ) column_defs = [ {"field": "country"}, { "field": "pop", "headerName": "Population", "editable": True, "cellEditor": rxe.ag_grid.editors.number, }, { "field": "continent", "editable": True, "cellEditor": rxe.ag_grid.editors.select, "cellEditorParams": { "values": ["Asia", "Europe", "Africa", "Americas", "Oceania"] }, }, ] def ag_grid_simple_editing(): return rxe.ag_grid( id="ag_grid_basic_editing", row_data=AGGridEditingState.data, column_defs=column_defs, on_cell_value_changed=AGGridEditingState.cell_value_changed, on_mount=AGGridEditingState.load_data, width="100%", height="40vh", ) ``` ## Pagination By default, the grid uses a vertical scroll. You can reduce the amount of scrolling required by adding pagination. To add pagination, set `pagination=True`. You can set the `pagination_page_size` to the number of rows per page and `pagination_page_size_selector` to a list of options for the user to select from. ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country"}, {"field": "pop", "headerName": "Population"}, {"field": "lifeExp", "headerName": "Life Expectancy"}, ] def ag_grid_simple_pagination(): return rxe.ag_grid( id="ag_grid_basic_pagination", row_data=df.to_dict("records"), column_defs=column_defs, pagination=True, pagination_page_size=10, pagination_page_size_selector=[10, 40, 100], width="100%", height="40vh", ) ``` 📊 **Dataset source:** [gapminder2007.csv](https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv) ## AG Grid with State ### Putting Data in State Assuming you want to make any edit to your data, you can put the data in State. This allows you to update the grid based on user input. Whenever the `data` var is updated, the grid will be re-rendered with the new data. ```python from typing import Any import reflex as rx import reflex_enterprise as rxe import pandas as pd class AGGridState2(rx.State): data: list[dict] = [] @rx.event def load_data(self): _df = pd.read_csv("data/gapminder2007.csv") self.data = _df.to_dict("records") column_defs = [ {"field": "country"}, {"field": "pop", "headerName": "Population"}, {"field": "continent"}, ] def ag_grid_state_2(): return rxe.ag_grid( id="ag_grid_state_2", row_data=AGGridState2.data, column_defs=column_defs, on_mount=AGGridState2.load_data, width="100%", height="40vh", ) ``` ### Updating the Grid with State You can use State to update the grid based on a users input. In this example, we update the `column_defs` of the grid when a user clicks a button. ```python import reflex as rx import reflex_enterprise as rxe import pandas as pd class AgGridState(rx.State): """The app state.""" all_columns: list = [] two_columns: list = [] column_defs: list = all_columns n_clicks = 0 @rx.event def init_columns(self): self.all_columns = [ {"field": "country"}, {"field": "pop"}, {"field": "continent"}, {"field": "lifeExp"}, {"field": "gdpPercap"}, ] self.two_columns = [ {"field": "country"}, {"field": "pop"}, ] self.column_defs = self.all_columns @rx.event def update_columns(self): self.n_clicks += 1 if self.n_clicks % 2 != 0: self.column_defs = self.two_columns else: self.column_defs = self.all_columns df = pd.read_csv("data/gapminder2007.csv") def ag_grid_simple_with_state(): return rx.box( rx.button("Toggle Columns", on_click=AgGridState.update_columns), rxe.ag_grid( id="ag_grid_basic_with_state", row_data=df.to_dict("records"), column_defs=AgGridState.column_defs, on_mount=AgGridState.init_columns, width="100%", height="40vh", ), width="100%", ) ``` 📊 **Dataset source:** [gapminder2007.csv](https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv) ## AG Grid with Data from a Database In this example, we will use a database to store the data. The data is loaded from a csv file and inserted into the database when the page is loaded using the `insert_dataframe_to_db` event handler. The data is then fetched from the database and displayed in the grid using the `data` computed var. When a cell value is changed, the data is updated in the database using the `cell_value_changed` event handler. ```python import reflex as rx import reflex_enterprise as rxe import pandas as pd from sqlmodel import select class Country(rx.Model, table=True): country: str population: int continent: str class AGGridDatabaseState(rx.State): countries: list[Country] # Insert data from a csv loaded dataframe to the database (Do this on the page load) @rx.event def insert_dataframe_to_db(self): data = pd.read_csv("data/gapminder2007.csv") with rx.session() as session: for _, row in data.iterrows(): db_record = Country( country=row["country"], population=row["pop"], continent=row["continent"], ) session.add(db_record) session.commit() # Fetch data from the database using a computed variable @rx.var def data(self) -> list[dict]: with rx.session() as session: results = session.exec(select(Country)).all() self.countries = [result.dict() for result in results] return self.countries # Update the database when a cell value is changed @rx.event def cell_value_changed(self, row, col_field, new_value): self.countries[row][col_field] = new_value with rx.session() as session: country = Country(**self.countries[row]) session.merge(country) session.commit() yield rx.toast( f"Cell value changed, Row: {row}, Column: {col_field}, New Value: {new_value}" ) column_defs = [ {"field": "country"}, { "field": "population", "headerName": "Population", "editable": True, "cellEditor": rxe.ag_grid.editors.number, }, { "field": "continent", "editable": True, "cellEditor": rxe.ag_grid.editors.select, "cellEditorParams": { "values": ["Asia", "Europe", "Africa", "Americas", "Oceania"] }, }, ] def index(): return rxe.ag_grid( id="ag_grid_basic_editing", row_data=AGGridDatabaseState.data, column_defs=column_defs, on_cell_value_changed=AGGridDatabaseState.cell_value_changed, width="100%", height="40vh", ) # Add state and page to the app. app = rx.App() app.add_page(index, on_load=AGGridDatabaseState.insert_dataframe_to_db) ``` ## Using AG Grid Enterprise AG Grid offers both community and enterprise versions. See the [AG Grid docs](https://www.ag-grid.com/archive/31.2.0/react-data-grid/licensing/) for details on purchasing a license key. To use an AG Grid Enterprise license key with Reflex AG Grid set the environment variable `AG_GRID_LICENSE_KEY`: ```bash export AG_GRID_LICENSE_KEY="your_license_key" ``` ## column_def props The following props are available for `column_defs` as well as many others that can be found here: [AG Grid Column Def Docs](https://www.ag-grid.com/react-data-grid/column-properties/). (it is necessary to use snake_case for the keys in Reflex, unlike in the AG Grid docs where camelCase is used) - `field`: `str`: The field of the row object to get the cell's data from. - `col_id`: `str | None`: The unique ID to give the column. This is optional. If missing, the ID will default to the field. - `type`: `str | None`: The type of the column. - `cell_data_type`: `bool | str | None`: The data type of the cell values for this column. Can either infer the data type from the row data (true - the default behaviour), define a specific data type (string), or have no data type (false). - `hide`: `bool`: Set to true for this column to be hidden. - `editable`: `bool | None`: Set to true if this column is editable, otherwise false. - `filter`: `AGFilters | str | None`: Filter component to use for this column. Set to true to use the default filter. Set to the name of a provided filter to use that filter. (Check out the Filter Types section of this page for more information) - `floating_filter`: `bool`: Whether to display a floating filter for this column. - `header_name`: `str | None`: The name to render in the column header. If not specified and field is specified, the field name will be used as the header name. - `header_tooltip`: `str | None`: Tooltip for the column header. - `checkbox_selection`: `bool | None`: Set to true to render a checkbox for row selection. - `cell_editor`: `AGEditors | str | None`: Provide your own cell editor component for this column's cells. (Check out the Editing section of this page for more information) - `cell_editor_params`: `dict[str, list[Any]] | None`: Params to be passed to the cellEditor component. ## Functionality you need is not available/working in Reflex All AGGrid options found in this [documentation](https://www.ag-grid.com/react-data-grid/reference/) are mapped in rxe.ag_grid, but some features might not have been fully tested, due to the sheer number of existing features in the underlying AG Grid library. If one of the ag_grid props does not import the expected module, you can pass it manually via the props `community_modules` or `enterprise_modules`, which expect a `set[str]` of the module names. You will get a warning in the browser console if a module is missing, so you can check there if a feature is not working as expected. You can also report the missing module on our discord or GitHub issues page of the main Reflex repository. Best practice is to create a single instance of `ag_grid.api()` with the same `id` as the `id` of the `ag_grid` component that is to be referenced, `"ag_grid_basic_row_selection"` in this first example. The example below uses the `select_all()` and `deselect_all()` methods of the AG Grid API to select and deselect all rows in the grid. This method is not available in Reflex directly. Check out this [documentation](https://www.ag-grid.com/react-data-grid/grid-api/#reference-selection-selectAll) to see what the methods look like in the AG Grid docs. ```md alert info # Ensure that the docs are set to React tab in AG Grid ``` ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country", "checkboxSelection": True}, {"field": "pop"}, {"field": "continent"}, ] def ag_grid_api_simple(): my_api = rxe.ag_grid.api(id="ag_grid_basic_row_selection") return rx.vstack( rxe.ag_grid( id="ag_grid_basic_row_selection", row_data=df.to_dict("records"), column_defs=column_defs, row_selection="single", width="100%", height="40vh", ), rx.button("Select All", on_click=my_api.select_all()), rx.button("Deselect All", on_click=my_api.deselect_all()), spacing="4", width="100%", ) ``` 📊 **Dataset source:** [gapminder2007.csv](https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv) The react code for the `select_all()` event handler is `selectAll = (source?: SelectionEventSourceType) => void;`. To use this in Reflex as you can see, it should be called in snake case rather than camel case. The `void` means it doesn't return anything. The `source?` indicates that it takes an optional `source` argument. ```md alert info # Another way to use the AG Grid API It is also possible to use the AG Grid API directly with the event trigger (`on_click`) of the component. This removes the need to create a variable `my_api`. This is shown in the example below. It is necessary to use the `id` of the `ag_grid` component that is to be referenced. ```python rx.button("Select all", on_click=rxe.ag_grid.api(id="ag_grid_basic_row_selection").select_all()), ``` ``` ### More examples The following example lets a user [export the data as a csv](https://www.ag-grid.com/javascript-data-grid/grid-api/#reference-export-exportDataAsCsv) and [adjust the size of columns to fit the available horizontal space](https://www.ag-grid.com/javascript-data-grid/grid-api/#reference-columnSizing-sizeColumnsToFit). (Try resizing the screen and then clicking the resize columns button) ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country", "checkboxSelection": True}, {"field": "pop"}, {"field": "continent"}, ] def ag_grid_api_simple2(): my_api = rxe.ag_grid.api(id="ag_grid_export_and_resize") return rx.vstack( rxe.ag_grid( id="ag_grid_export_and_resize", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", height="40vh", ), rx.button("Export", on_click=my_api.export_data_as_csv()), rx.button("Resize Columns", on_click=my_api.size_columns_to_fit()), spacing="4", width="100%", ) ``` 📊 **Dataset source:** [gapminder2007.csv](https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv) The react code for both of these is shown below. The key point to see is that both of these functions return `void` and therefore does not return anything. `exportDataAsCsv = (params?: CsvExportParams) => void;` `sizeColumnsToFit = (paramsOrGridWidth?: ISizeColumnsToFitParams | number) => void;` ### Example with a Return Value This example shows how to get the data from `ag_grid` as a [csv on the backend](https://www.ag-grid.com/javascript-data-grid/grid-api/#reference-export-getDataAsCsv). The data that was passed to the backend is then displayed as a toast with the data. ```python import reflex as rx import reflex_enterprise as rxe import pandas as pd class AGGridStateAPI(rx.State): def handle_get_data(self, data: str): yield rx.toast(f"Got CSV data: {data}") df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country", "checkboxSelection": True}, {"field": "pop"}, {"field": "continent"}, ] def ag_grid_api_argument(): my_api = rxe.ag_grid.api(id="ag_grid_get_data_as_csv") return rx.vstack( rxe.ag_grid( id="ag_grid_get_data_as_csv", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", height="40vh", ), rx.button( "Get CSV data on backend", on_click=my_api.get_data_as_csv(callback=AGGridStateAPI.handle_get_data), ), spacing="4", width="100%", ) ``` The react code for the `get_data_as_csv` method of the AG Grid API is `getDataAsCsv = (params?: CsvExportParams) => string | undefined;`. Here the function returns a `string` (or undefined). In Reflex to handle this returned value it is necessary to pass a `callback` as an argument to the `get_data_as_csv` method that will get the returned value. In this example the `handle_get_data` event handler is passed as the callback. This event handler will be called with the returned value from the `get_data_as_csv` method. # Model Wrapper Source: http://localhost:3000/docs/enterprise/ag-grid/model-wrapper.md --- order: 6 --- A model wrapper is an utility used to wrap a database model and provide a consistent interface over it. It allows automatically adding new rows to the database, updating existing rows, and deleting rows. ## Default Model Wrapper You can use the basic functionality of the model wrapper by using the `rxe.model_wrapper` function. This function takes a database model and returns a wrapper object that can be used to interact with the model. ```python import reflex_enterprise as rxe def index_page(): return rxe.model_wrapper(class_model=MyModel) ``` By default the model_wrapper use the infinite rows model from AgGrid. ## Custom Model Wrapper If the default model wrapper does not fit your needs, you can create a custom model wrapper by subclassing the `rxe.ModelWrapper` class. This allows you to customize the behavior of the model wrapper to fit your specific use case. ```python import reflex_enterprise as rxe class MyCustomWrapper(rxe.ModelWrapper[MyModel]): pass ``` In the custom model wrapper, you can override the following methods: - `_get_columns_defs` - `_get_data` - `_row_count` - `on_value_setter` to modify how the model wrapper will behave. ## SSRM Model Wrapper The SSRM model wrapper, used with `rxe.model_wrapper_ssrm`, is a version of the model wrapper that allows you to use the ServerSideRowModel of AgGrid. ```python import reflex_enterprise as rxe def index_page(): return rxe.model_wrapper_ssrm(class_model=MyModel) ``` ## SSRM Custom Model Wrapper In the same way you can extend the default model wrapper, you can extend the SSRM custom model wrapper by subclassing the `rxe.ModelWrapperSSRM` class. This allows you to customize the behavior of the model wrapper to fit your specific use case. ```python import reflex_enterprise as rxe class MyCustomSSRMWrapper(rxe.ModelWrapperSSRM[MyModel]): pass ``` The overridable methods are the same as the standard model wrapper. # Pivot Mode Source: http://localhost:3000/docs/enterprise/ag-grid/pivot-mode.md ```python exec import reflex as rx import reflex_enterprise as rxe ``` Pivot mode allows you to visualize your data in a different way than how they are originally structured in the data source. When pivoting on a column, the values in that column will be used as column headers. This allows you to see the data in a more compact way, and can be useful when you have a lot of data to display. To enable pivot mode, set the `pivot_mode` property to `True` in the grid props. Once pivot mode is enabled, you can define which column to pivot on by setting the `pivot` property in a column definition. In addition to the pivot column, at least one column definition must have `row_group` property set to `True` to define the row grouping. You can also define how rows are aggregated by passing the `agg_func` property in the column definition. The `agg_func` property should be set to a string that represents the aggregation function to use. The built-in aggregation functions are `sum`, `min`, `max`, `count`, `avg`, `first`, and `last`. You can find a live example here: [Pivot Mode Example](https://aggrid.reflex.run/pivot). ```python demo exec import pandas as pd import reflex as rx import reflex_enterprise as rxe # Olympic winners data (originally from https://www.ag-grid.com/example-assets/olympic-winners.json) df = pd.read_json("data/olympic-winners.json") def pivot_page(): return ( rxe.ag_grid( id="sandbox_grid", column_defs=[ {"field": "country", "row_group": True}, {"field": "sport", "pivot": True}, {"field": "year", "pivot": True}, {"field": "gold", "aggFunc": "sum"}, ], loading=False, row_data=df.to_dict("records"), default_col_def={ "flex": 1, "min_width": 130, "enable_value": True, "enable_row_group": True, "enable_pivot": True, }, auto_group_column_def={ "minWidth": 200, "pinned": "left", }, pivot_mode=True, side_bar="columns", pivot_panel_show="always", width="100%", height="500px", ), ) ``` # Pivot using State ```python demo exec import pandas as pd import reflex as rx import reflex_enterprise as rxe df = pd.read_csv("data/wind_dataset.csv") class PivotState(rx.State): """State for the sandbox page.""" pivot = False row_grouping = False @rx.event def toggle_pivot(self): """Toggle the pivot.""" self.pivot = not self.pivot @rx.event def toggle_row_grouping(self): """Toggle the row grouping.""" self.row_grouping = not self.row_grouping def sandbox_page(): """Sandbox page.""" return rx.vstack( rx.hstack( rx.text("Toggle Pivot"), rx.switch( on_click=PivotState.toggle_pivot, name="pivot", checked=PivotState.pivot, ), rx.text("Toggle Row Grouping"), rx.switch( on_click=PivotState.toggle_row_grouping, name="row_grouping", checked=PivotState.row_grouping, ), ), rxe.ag_grid( id="sandbox_grid", column_defs=[ rxe.ag_grid.column_def( field="direction", pivot=True, ), rxe.ag_grid.column_def( field="strength", ), rxe.ag_grid.column_def( field="frequency", agg_func="count", row_group=PivotState.row_grouping, ), ], row_data=df.to_dict("records"), pivot_mode=PivotState.pivot, pivot_panel_show="onlyWhenPivoting", width="100%", height="500px", ), width="100%", ) ``` 📊 **Dataset source:** [wind_dataset.csv](https://raw.githubusercontent.com/plotly/datasets/master/wind_dataset.csv) # Themes Source: http://localhost:3000/docs/enterprise/ag-grid/theme.md --- order: 3 --- ```python exec import reflex as rx import reflex_enterprise as rxe ``` ```md alert warning # Only the old theme API of AG Grid is currently supported. The new theme API is not supported yet. ``` You can style your grid with a theme. AG Grid includes the following themes: 1. `quartz` 2. `alpine` 3. `balham` 4. `material` The grid uses `quartz` by default. To use any other theme, set it using the `theme` prop, i.e. `theme="alpine"`. ```python import reflex as rx import reflex_enterprise as rxe import pandas as pd class AGGridThemeState(rx.State): """The app state.""" theme: str = "quartz" themes: list[str] = ["quartz", "balham", "alpine", "material"] df = pd.read_csv("data/gapminder2007.csv") column_defs = [ {"field": "country"}, {"field": "pop", "headerName": "Population"}, {"field": "lifeExp", "headerName": "Life Expectancy"}, ] def ag_grid_simple_themes(): return rx.vstack( rx.hstack( rx.text("Theme:"), rx.select( AGGridThemeState.themes, value=AGGridThemeState.theme, on_change=AGGridThemeState.set_theme, ), ), rxe.ag_grid( id="ag_grid_basic_themes", row_data=df.to_dict("records"), column_defs=column_defs, theme=AGGridThemeState.theme, width="100%", height="40vh", ), width="100%", ) ``` 📊 **Dataset source:** [gapminder2007.csv](https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv) ## Customizing a Theme with CSS The `theme` prop maps directly to one of AG Grid's built-in theme classes, which `reflex-enterprise` applies on the grid root element: - `theme="quartz"` → `.ag-theme-quartz` - `theme="balham"` → `.ag-theme-balham` - `theme="alpine"` → `.ag-theme-alpine` - `theme="material"` → `.ag-theme-material` Each theme also has a dark variant (`.ag-theme-quartz-dark`, `.ag-theme-balham-dark`, etc.). The dark variant is only applied when the corresponding theme name is selected; listing both light and dark class selectors in your CSS lets the same overrides apply in either mode. You can customize any theme by overriding the AG Grid CSS variables (the `--ag-*` custom properties) and by writing rules that target AG Grid's built-in classes. The full list of available variables is documented in the [AG Grid theming reference](https://www.ag-grid.com/javascript-data-grid/global-style-customisation-variables/). ### CSS Variables AG Grid exposes most visual properties as CSS variables. Commonly customized ones: - Typography: `--ag-font-family`, `--ag-font-size` - Density and shape: `--ag-grid-size` (base unit), `--ag-border-radius`, `--ag-wrapper-border-radius`, `--ag-cell-horizontal-padding` - Borders: `--ag-border-color`, `--ag-row-border-color` - Backgrounds: `--ag-background-color`, `--ag-odd-row-background-color`, `--ag-row-hover-color` - Headers: `--ag-header-background-color`, `--ag-header-foreground-color`, `--ag-header-column-separator-color` - Accents (selection / focus): `--ag-accent-color`, `--ag-selected-row-background-color`, `--ag-range-selection-background-color`, `--ag-input-focus-border-color`, `--ag-checkbox-checked-color` ### Scoping Overrides with a Wrapper Class If you have multiple grids on a page, scope your overrides to a parent class so they don't leak to other grids. Wrap the grid in an `rx.box` (or any element) with a class such as `custom-ag-grid`, then target the theme class _inside_ that wrapper in your CSS: ```python rx.box( rxe.ag_grid( id="my_themed_grid", row_data=df.to_dict("records"), column_defs=column_defs, theme="quartz", width="100%", height="40vh", ), class_name="custom-ag-grid", ) ``` ```css /* assets/ag_grid_theme.css */ /* * Custom ag-grid theme overrides. * * reflex-enterprise applies the built-in theme as a class on the grid root. * Scope overrides to a parent `.custom-ag-grid` container so they don't leak * to other grids on the page. */ .custom-ag-grid .ag-theme-quartz, .custom-ag-grid .ag-theme-quartz-dark, .custom-ag-grid .ag-theme-balham, .custom-ag-grid .ag-theme-balham-dark, .custom-ag-grid .ag-theme-alpine, .custom-ag-grid .ag-theme-alpine-dark, .custom-ag-grid .ag-theme-material, .custom-ag-grid .ag-theme-material-dark { --ag-font-family: "Inter", ui-sans-serif, system-ui, sans-serif; --ag-font-size: 13px; --ag-grid-size: 6px; --ag-border-radius: 12px; --ag-wrapper-border-radius: 12px; --ag-background-color: #ffffff; --ag-odd-row-background-color: #fafbfd; --ag-row-hover-color: #f1f5f9; --ag-header-background-color: #eef2ff; --ag-header-foreground-color: #1e293b; --ag-accent-color: #3b82f6; --ag-selected-row-background-color: #dbeafe; --ag-input-focus-border-color: #3b82f6; --ag-checkbox-checked-color: #3b82f6; --ag-cell-horizontal-padding: 16px; } /* Stronger header typography. */ .custom-ag-grid .ag-header-cell-text { font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; font-size: 11px; } ``` Listing every theme variant in the selector keeps the overrides applied no matter which built-in theme is selected at runtime, including its dark variant. ### Loading the Stylesheet Place your CSS file under `assets/` and add it to the `stylesheets` list on your `rxe.App` (or `rx.App`): ```python app = rxe.App( stylesheets=["/ag_grid_theme.css"], ) ``` The path is relative to `assets/`, so `assets/ag_grid_theme.css` is referenced as `/ag_grid_theme.css`. ### Overriding CSS Variables Inline via `style` For one-off tweaks you don't need a separate stylesheet — you can set `--ag-*` variables directly in the `style` dict on the grid: ```python rxe.ag_grid( id="comic_grid", row_data=df.to_dict("records"), column_defs=column_defs, theme="quartz", style={ "--ag-font-family": "Comic Sans MS !important", "--ag-font-size": "14px !important", }, width="100%", height="40vh", ) ``` ```md alert warning # CSS variable inheritance and `!important` Inline `style` sets the variable on the grid root element only. The built-in themes bind their styling to multiple CSS classes (`.ag-theme-quartz`, `.ag-theme-quartz .ag-cell`, etc.), and those rules often have higher specificity than a custom property defined inline. As a result, a value set via `style={"--ag-font-family": "..."}` may be ignored unless you append `!important`. If your inline override doesn't take effect, add `!important` or move the override into a stylesheet that targets the theme class with comparable specificity. Inline `style` overrides only apply to the grid they are set on. To customize multiple grids consistently, prefer a stylesheet scoped to a wrapper class (see above). ``` ## Per-Cell Custom Classes Built-in themes style the grid as a whole. To highlight individual cells based on their value, attach custom CSS classes via the `cellClass` and `cellClassRules` column-def keys, then style those classes in your stylesheet. - `cellClass` always applies the listed class(es) to every cell in the column. - `cellClassRules` is a mapping of `class name -> JS expression`; the class is applied when the expression evaluates truthy. The cell's value is available as `params.value`. ```python column_defs = [ {"field": "project"}, { "field": "status", "cellClass": "status-pill", "cellClassRules": { "status-active": "params.value === 'Active'", "status-blocked": "params.value === 'Blocked'", "status-complete": "params.value === 'Complete'", "status-planning": "params.value === 'Planning'", }, }, ] ``` ```css /* assets/ag_grid_theme.css */ .custom-ag-grid .status-pill { display: inline-flex; align-items: center; justify-content: center; } .custom-ag-grid .status-active { color: #047857; } .custom-ag-grid .status-blocked { color: #b91c1c; } .custom-ag-grid .status-complete { color: #1d4ed8; } .custom-ag-grid .status-planning { color: #a16207; } ``` The same approach works for header cells (`headerClass`) and rows (`rowClass` / `rowClassRules` on the grid itself). # Value Transformers Source: http://localhost:3000/docs/enterprise/ag-grid/value-transformers.md --- order: 2 --- ```python exec import reflex as rx import reflex_enterprise as rxe ``` AgGrid allow you to apply transformers based on the column of your grid. This allow you to perform operations on the data before displaying it on the grid, without having to pre-process the data on the backend, reducing the load on your application. TOC: - [Value Getter](#value-getter) - [Value Formatter](#value-formatter) ## Value Getter `value_getter` is a property of the column definition that allows you to define a function that will be called to get the value of the cell. This function will receive the row data as a parameter and should return the value to be displayed on the cell. If you have two columns `col_a` and `col_b` and you want to display the sum of these two columns in a third column `sum`, you can define the `value_getter` of `sum` as follows: ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.DataFrame({"col_a": [1, 2, 3, 4, 5], "col_b": [10, 20, 30, 40, 50]}) column_defs = [ {"field": "col_a", "header_name": "Column A"}, {"field": "col_b", "header_name": "Column B"}, { "field": "sum", "header_name": "Sum", "value_getter": "params.data.col_a + params.data.col_b", }, rxe.ag_grid.column_def( field="diff", header_name="Difference", value_getter="params.data.col_b - params.data.col_a", ), ] def ag_grid_value_getter(): return rxe.ag_grid( id="ag_grid_value_getter", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", ) ``` ## Value Formatter `value_formatter` is a property of the column definition that allows you to define a function that will be called to format the value of the cell. This function will receive the value of the cell as a parameter and should return the formatted value to be displayed on the cell. If you have a column `price` and you want to display the price with a currency symbol, you can define the `value_formatter` of `price` as follows: ```python demo exec import reflex as rx import reflex_enterprise as rxe import pandas as pd df = pd.DataFrame({ "product_name": ["Product A", "Product B", "Product C", "Product D", "Product E"], "price": [100, 200, 300, 400, 500], }) column_defs = [ {"field": "product_name", "header_name": "Product Name"}, { "field": "price", "header_name": "Price ($)", "value_formatter": "'$' + params.value", }, rxe.ag_grid.column_def( col_id="price_eur", header_name="Price (€)", value_formatter="params.data.price + ' €'", ), ] def ag_grid_value_formatter(): return rxe.ag_grid( id="ag_grid_value_formatter", row_data=df.to_dict("records"), column_defs=column_defs, width="100%", ) ``` # Built with Reflex Badge Source: http://localhost:3000/docs/enterprise/built-with-reflex.md The "Built with Reflex" badge appears in the bottom right corner of apps using reflex-enterprise components. ## Removing the Badge To remove the badge, you need to be on the Enterprise tier. ## Configuration ```python import reflex_enterprise as rxe config = rxe.Config( show_built_with_reflex=False, # Requires paid tier ) ``` # Components Source: http://localhost:3000/docs/enterprise/components.md --- title: Enterprise Components --- ```python exec import reflex as rx def enterprise_component_grid(): sections = [ { "title": "AG Grid", "description": "Advanced data grid with sorting, filtering, editing, and pagination", "link": "/docs/enterprise/ag-grid/", "components": [ ("Overview", "/docs/enterprise/ag-grid/"), ("Column Definitions", "/docs/enterprise/ag-grid/column-defs/"), ("Aligned Grids", "/docs/enterprise/ag-grid/aligned-grids/"), ("Model Wrapper", "/docs/enterprise/ag-grid/model-wrapper/"), ("Pivot Mode", "/docs/enterprise/ag-grid/pivot-mode/"), ("Theme", "/docs/enterprise/ag-grid/theme/"), ("Value Transformers", "/docs/enterprise/ag-grid/value-transformers/"), ], }, { "title": "AG Chart", "description": "Interactive charts and data visualization", "link": "/docs/enterprise/ag-chart/", "components": [ ("Overview", "/docs/enterprise/ag-chart/"), ], }, { "title": "Interactive Components", "description": "Drag-and-drop and mapping functionality", "link": "/docs/enterprise/drag-and-drop/", "components": [ ("Drag and Drop", "/docs/enterprise/drag-and-drop/"), ("Mapping", "/docs/enterprise/map/"), ], }, { "title": "Mantine", "description": "Rich UI components from Mantine library", "link": "/docs/enterprise/mantine/", "components": [ ("Overview", "/docs/enterprise/mantine/"), ("Autocomplete", "/docs/enterprise/mantine/autocomplete/"), ("Collapse", "/docs/enterprise/mantine/collapse/"), ("Combobox", "/docs/enterprise/mantine/combobox/"), ("JSON Input", "/docs/enterprise/mantine/json-input/"), ("Loading Overlay", "/docs/enterprise/mantine/loading-overlay/"), ("Multi Select", "/docs/enterprise/mantine/multi-select/"), ("Number Formatter", "/docs/enterprise/mantine/number-formatter/"), ("Pill", "/docs/enterprise/mantine/pill/"), ("Ring Progress", "/docs/enterprise/mantine/ring-progress/"), ( "Semi Circle Progress", "/docs/enterprise/mantine/semi-circle-progress/", ), ("Spoiler", "/docs/enterprise/mantine/spoiler/"), ("Tags Input", "/docs/enterprise/mantine/tags-input/"), ("Timeline", "/docs/enterprise/mantine/timeline/"), ("Tree", "/docs/enterprise/mantine/tree/"), ], }, ] cards = [] for section in sections: cards.append( rx.box( rx.link( rx.el.h1( section["title"], class_name="font-large text-slate-12", ), rx.icon("arrow_up_right", size=16, class_name="text-slate-11"), href=section["link"], underline="none", class_name="px-4 py-2 bg-slate-1 hover:bg-slate-3 transition-bg flex flex-row justify-between items-center !text-slate-12", ), rx.text( section["description"], class_name="px-4 py-2 font-small text-slate-9 border-t border-slate-5", ), rx.box( *[ rx.link( comp[0], href=comp[1], class_name="font-small text-slate-11 hover:!text-violet-9 transition-color w-fit", ) for comp in section["components"] ], class_name="flex flex-col gap-2.5 px-4 py-2 border-t border-slate-5", ), class_name="flex flex-col border border-slate-5 rounded-xl bg-slate-2 shadow-large overflow-hidden", ) ) return rx.box( *cards, class_name="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-8", ) component_grid = enterprise_component_grid() ``` ```python eval rx.el.h1( "Enterprise Components", class_name="lg:text-5xl text-3xl font-[525] scroll-mt-[113px] my-4 text-secondary-12", ) ``` ```python eval rx.el.span( "Advanced UI components and features to enhance your Reflex applications. Available for free with the 'Built with Reflex' badge, or without the badge with an enterprise license.", class_name="font-[475] text-secondary-11 max-w-[80%] text-sm", ) ``` ```python eval component_grid ``` # Drag and Drop Source: http://localhost:3000/docs/enterprise/drag-and-drop.md --- title: Drag and Drop --- ```python exec import reflex as rx import reflex_enterprise as rxe ``` Reflex Enterprise provides comprehensive drag and drop functionality for creating interactive UI elements using the `rxe.dnd` module. Built on top of react-dnd, it offers both high-level components for common use cases and low-level hooks for advanced scenarios. ```md alert warning # Important: Always decorate functions defining `rxe.dnd.draggable` components with `@rx.memo` to avoid compilation errors. ``` ## Basic Usage ### Simple Drag and Drop Here's a basic example showing how to create a draggable item and drop target: ```python demo exec import reflex as rx import reflex_enterprise as rxe class BasicDndState(rx.State): drop_count: int = 0 def increment_drop_count(self): self.drop_count += 1 @rx.memo def draggable_card(): return rxe.dnd.draggable( rx.card( rx.text("Drag me!", weight="bold"), rx.text("I can be moved around"), bg="blue.500", color="white", p=4, cursor="grab", width="200px", height="100px", ), type="BasicCard", item={"message": "Hello from draggable!"}, ) def basic_drag_drop(): return rx.vstack( rx.text(f"Items dropped: {BasicDndState.drop_count}"), rx.hstack( draggable_card(), rxe.dnd.drop_target( rx.box( "Drop Zone", bg="gray.100", border="2px dashed gray", min_height="150px", min_width="200px", display="flex", align_items="center", justify_content="center", font_weight="bold", ), accept=["BasicCard"], on_drop=BasicDndState.increment_drop_count, ), spacing="4", align="start", ), spacing="4", ) ``` ### Multi-Position Drag and Drop Create a draggable item that can be moved between multiple drop targets: ```python demo exec import reflex as rx import reflex_enterprise as rxe class MultiPositionState(rx.State): card_position: int = 0 def set_card_position(self, position: int): self.card_position = position @rx.memo def movable_card(): return rxe.dnd.draggable( rx.card( rx.text("Movable Card", weight="bold"), rx.text("Position: " + MultiPositionState.card_position.to_string()), bg="purple.500", color="white", p=4, width="180px", height="120px", ), type="MovableCard", border="2px solid purple", ) def drop_zone(position: int): params = rxe.dnd.DropTarget.collected_params return rxe.dnd.drop_target( rx.cond( MultiPositionState.card_position == position, movable_card(), rx.box(f"Drop Zone {position}", color="gray.600", font_weight="bold"), ), width="200px", height="200px", border="2px solid red", border_color=rx.cond(params.is_over, "green.500", "red.500"), bg=rx.cond(params.is_over, "green.100", "blue.100"), accept=["MovableCard"], on_drop=lambda _: MultiPositionState.set_card_position(position), display="flex", align_items="center", justify_content="center", ) def multi_position_example(): return rx.vstack( rx.text("Drag the card between positions", weight="bold"), rx.grid( drop_zone(0), drop_zone(1), drop_zone(2), drop_zone(3), columns="2", spacing="4", ), spacing="4", ) ``` ## Advanced Features ### State Tracking with Collected Parameters Access drag and drop state information using collected parameters: ```python demo exec import reflex as rx import reflex_enterprise as rxe class StateTrackingState(rx.State): drag_info: str = "No drag activity" def set_drag_info(self, value: str): self.drag_info = value @rx.memo def tracked_draggable(): drag_params = rxe.dnd.Draggable.collected_params return rxe.dnd.draggable( rx.card( rx.text("Tracked Draggable"), rx.text(rx.cond(drag_params.is_dragging, "Dragging...", "Ready to drag")), bg=rx.cond(drag_params.is_dragging, "orange.500", "blue.500"), color="white", p=4, opacity=rx.cond(drag_params.is_dragging, 0.5, 1.0), ), type="TrackedItem", on_end=StateTrackingState.set_drag_info("Drag ended"), ) def tracked_drop_target(): drop_params = rxe.dnd.DropTarget.collected_params return rxe.dnd.drop_target( rx.box( rx.text("Smart Drop Zone"), rx.text(rx.cond(drop_params.is_over, "Ready to receive!", "Waiting...")), bg=rx.cond(drop_params.is_over, "green.200", "gray.100"), border=rx.cond(drop_params.is_over, "2px solid green", "2px dashed gray"), p=4, min_height="150px", display="flex", flex_direction="column", align_items="center", justify_content="center", ), accept=["TrackedItem"], on_drop=StateTrackingState.set_drag_info("Item successfully dropped!"), on_hover=StateTrackingState.set_drag_info("Item hovering over drop zone"), ) def state_tracking_example(): return rx.vstack( rx.text(f"Status: {StateTrackingState.drag_info}"), rx.hstack(tracked_draggable(), tracked_drop_target(), spacing="4"), spacing="4", ) ``` ### Dynamic Lists with Drag and Drop Create dynamic draggable lists using `rx.foreach`: ```python demo exec import dataclasses import reflex as rx import reflex_enterprise as rxe @dataclasses.dataclass class ListItem: id: str text: str list_id: str class DynamicListState(rx.State): list_a: list[ListItem] = [ ListItem(id="1", text="Item 1", list_id="A"), ListItem(id="2", text="Item 2", list_id="A"), ListItem(id="3", text="Item 3", list_id="A"), ] list_b: list[ListItem] = [ ListItem(id="4", text="Item 4", list_id="B"), ListItem(id="5", text="Item 5", list_id="B"), ] def move_item(self, item_data: dict, target_list: str): item_id = item_data.get("id") source_list = item_data.get("list_id") if not item_id or not source_list: return # Find the item in the source list source_items = getattr(self, f"list_{source_list.lower()}") item_to_move = None for item in source_items: if item.id == item_id: item_to_move = item break if not item_to_move: return # Remove from source list only if source_list == "A": self.list_a = [item for item in self.list_a if item.id != item_id] else: self.list_b = [item for item in self.list_b if item.id != item_id] # Create new item for target list new_item = ListItem(id=item_id, text=item_to_move.text, list_id=target_list) # Add to target list if target_list == "A": self.list_a.append(new_item) else: self.list_b.append(new_item) @rx.memo def draggable_list_item(item: ListItem): return rxe.dnd.draggable( rx.card( rx.text(item.text, weight="bold"), rx.text(f"From List {item.list_id}", size="2", color="gray.600"), p=3, cursor="grab", _hover={"bg": "gray.50"}, ), type="ListItem", item={"id": item.id, "text": item.text, "list_id": item.list_id}, ) def droppable_list(title: str, items: list[ListItem], list_id: str): return rxe.dnd.drop_target( rx.vstack( rx.text(title, weight="bold", size="5"), rx.vstack( rx.foreach(items, lambda item, index: draggable_list_item(item=item)), spacing="2", min_height="200px", width="100%", ), bg="gray.50", p=4, border_radius="md", border="2px dashed gray", width="250px", ), accept=["ListItem"], on_drop=lambda item: DynamicListState.move_item(item, list_id), ) def dynamic_list_example(): return rx.hstack( droppable_list("List A", DynamicListState.list_a, "A"), droppable_list("List B", DynamicListState.list_b, "B"), spacing="6", align="start", ) ``` ## Core Components ### Draggable The `rxe.dnd.draggable` component makes any element draggable: **Key Properties:** - `type`: String identifier for drag type matching - `item`: Data object passed to drop handlers - `on_end`: Called when drag operation ends ### Drop Target The `rxe.dnd.drop_target` component creates areas that accept draggable items: **Key Properties:** - `accept`: List of drag types this target accepts - `on_drop`: Called when item is dropped - `on_hover`: Called when item hovers over target ### Collected Parameters Access real-time drag/drop state: **Draggable Parameters (`rxe.dnd.Draggable.collected_params`):** - `is_dragging`: Boolean indicating if item is being dragged **Drop Target Parameters (`rxe.dnd.DropTarget.collected_params`):** - `is_over`: Boolean indicating if draggable is hovering - `can_drop`: Boolean indicating if drop is allowed # API Reference ### rxe.dnd.draggable Creates a draggable component that can be moved around the interface. **Parameters:** - **`type`** (str, required): String identifier that must match the `accept` list of drop targets - **`item`** (dict | Callable): Data object passed to drop handlers. Can be a static dictionary or a function that receives a `DragSourceMonitor` and returns data - **`preview_options`** (dict): Configuration for the drag preview appearance - **`options`** (dict): Additional drag source options like `dropEffect` - **`on_end`** (EventHandler): Event handler called when drag operation completes - **`can_drag`** (Callable): Function that determines if the item can be dragged - **`is_dragging`** (Callable): Function to override the default dragging state detection - **`collect`** (Callable): Function to collect custom properties from the drag monitor ### rxe.dnd.drop_target Creates a drop target that can receive draggable items. **Parameters:** - **`accept`** (str | list[str], required): Drag type(s) this target accepts - **`options`** (dict): Additional drop target configuration options - **`on_drop`** (EventHandler): Event handler called when an item is dropped, receives the `item` data - **`on_hover`** (EventHandler): Event handler called when an item hovers over the target - **`can_drop`** (Callable): Function that determines if a specific item can be dropped - **`collect`** (Callable): Function to collect custom properties from the drop monitor ## Monitor Classes ### DragSourceMonitor Provides information about the drag operation state: - **`is_dragging()`**: Returns `True` if this item is currently being dragged - **`can_drag()`**: Returns `True` if the item can be dragged - **`get_item()`**: Returns the item data being dragged - **`get_item_type()`**: Returns the drag type string - **`get_drop_result()`**: Returns the drop result (available in `on_end`) - **`did_drop()`**: Returns `True` if the item was successfully dropped ### DropTargetMonitor Provides information about the drop target state: - **`is_over()`**: Returns `True` if a draggable item is hovering over this target - **`can_drop()`**: Returns `True` if the hovering item can be dropped - **`get_item()`**: Returns the item data of the hovering draggable - **`get_item_type()`**: Returns the drag type of the hovering item ## Default Collected Parameters ### Draggable.collected_params ```python { "is_dragging": bool, # True when this item is being dragged "can_drag": bool, # True when this item can be dragged } ``` ### DropTarget.collected_params ```python { "is_over": bool, # True when a draggable is hovering "can_drop": bool, # True when the hovering item can be dropped "item": dict | None, # Data from the hovering draggable item } ``` ## Advanced Usage Examples ### Data Passing with Item Parameter The `item` parameter allows you to pass data from draggable components to drop handlers: ```python demo exec toggle import reflex as rx import reflex_enterprise as rxe class SimpleState(rx.State): message: str = "No items dropped yet" def set_message_from_item(self, item: dict): self.message = f"Dropped: {item['name']}" def simple_draggable(): return rxe.dnd.draggable( rx.box("Drag me!", p=4, bg="blue.100", border="1px solid blue", cursor="grab"), type="simple", item={"name": "test_item", "value": 42}, ) def simple_drop_target(): return rxe.dnd.drop_target( rx.box( rx.text(SimpleState.message), p=4, bg="gray.100", border="2px dashed gray", min_height="100px", ), accept=["simple"], on_drop=SimpleState.set_message_from_item, ) def item_data_example(): return rx.vstack(simple_draggable(), simple_drop_target(), spacing="4") ``` ### Custom Collect Functions The `collect` parameter allows you to access drag and drop state information in real-time: ```python demo exec toggle import reflex as rx import reflex_enterprise as rxe class CollectState(rx.State): drag_info: str = "No drag activity" drop_info: str = "No drop activity" def handle_drop(self, item: dict): self.drop_info = f"Dropped: {item.get('name', 'Unknown')}" return rx.toast(f"Successfully dropped {item.get('name', 'item')}") def collect_draggable(): params = rxe.dnd.Draggable.collected_params return rxe.dnd.draggable( rx.box( rx.vstack( rx.text("Drag me!", weight="bold"), rx.text(f"Dragging: {params.is_dragging}", size="2"), rx.text(f"Can drag: {params.can_drag}", size="2"), spacing="1", ), p=4, bg=rx.cond(params.is_dragging, "blue.200", "blue.100"), border="1px solid blue", cursor=rx.cond(params.is_dragging, "grabbing", "grab"), opacity=rx.cond(params.is_dragging, 0.7, 1.0), ), type="collect_item", item={"id": "collect_test", "name": "Test Item"}, ) def collect_drop_target(): params = rxe.dnd.DropTarget.collected_params return rxe.dnd.drop_target( rx.box( rx.vstack( rx.text("Drop Zone", weight="bold"), rx.text(f"Is over: {params.is_over}", size="2"), rx.text(f"Can drop: {params.can_drop}", size="2"), rx.cond( params.item, rx.text( f"Hovering item: {params.item.get('name', 'Unknown')}", size="2" ), rx.text("No item hovering", size="2"), ), spacing="1", ), p=4, bg=rx.cond( params.is_over & params.can_drop, "green.200", rx.cond(params.is_over, "yellow.200", "gray.100"), ), border=rx.cond( params.is_over & params.can_drop, "2px solid green", rx.cond(params.is_over, "2px solid yellow", "2px dashed gray"), ), min_height="120px", ), accept=["collect_item"], on_drop=CollectState.handle_drop, ) def custom_collect_example(): return rx.vstack( rx.text("Real-time Monitor State", weight="bold", size="4"), rx.hstack( collect_draggable(), collect_drop_target(), spacing="6", align="start" ), rx.text(CollectState.drop_info, size="2", color="gray.600"), spacing="4", ) ``` ## Provider Drag and drop functionality requires the `rxe.dnd.provider` component to wrap your app. The provider is automatically added when using `draggable` or `drop_target` components. For manual control: ```python def app(): return rxe.dnd.provider( # Your app content your_app_content(), backend="HTML5", # or "Touch" for mobile ) ``` ## Best Practices 1. **Always use `@rx.memo`** on functions containing draggable components 2. **Use descriptive type names** for better debugging 3. **Handle edge cases** in drop handlers (invalid items, etc.) 4. **Provide visual feedback** using collected parameters 5. **Test on mobile devices** with touch backend 6. **Keep item data lightweight** for better performance --- [← Back to main documentation](/docs/enterprise/overview/) # Event Handler API Plugin Source: http://localhost:3000/docs/enterprise/event-handler-api.md --- title: Event Handler API --- _New in reflex-enterprise v0.7.1._ `rxe.EventHandlerAPIPlugin` exposes every registered event handler on your Reflex state as an HTTP `POST` endpoint and auto-generates an OpenAPI 3 specification for them. This turns any Reflex app into a machine-driveable API without writing a single route by hand — great for LLM agents, CLI scripts, end-to-end tests, or external integrations that need to drive the same logic the frontend uses. ```md alert info # Requires `reflex >= 0.9.0` and `reflex-enterprise`. The plugin only works with `rxe.App`. ``` ## Endpoints When the plugin is enabled, the following routes are added to the backend: | Path | Purpose | | --- | --- | | `POST /_reflex/event//` | One endpoint per `@rx.event` handler on every state class. Streams state deltas as newline-delimited JSON. | | `POST /_reflex/retrieve_state` | Returns the full root state `.dict()` for the session token without re-hydrating client storage. | | `GET /_reflex/events/openapi.yaml` | Auto-generated OpenAPI 3 specification describing every endpoint above. | | `GET,HEAD /.well-known/api-catalog` | RFC 9727 API catalog pointing at the OpenAPI spec (RFC 9264 Linkset). | Handler argument names and type annotations are introspected to build each `requestBody` schema, and the docstring's first line becomes the endpoint `summary`. Handlers registered as page `on_load` triggers are listed in the `description` field of the spec so API consumers can tell which endpoint is invoked when a given page is "visited". ## Configuration Add the plugin to the `plugins` list of `rxe.Config` in `rxconfig.py`: ```python import reflex as rx import reflex_enterprise as rxe config = rxe.Config( app_name="my_app", plugins=[ rxe.EventHandlerAPIPlugin( # All three arguments are optional. api_version="1.0.0", contact={"name": "Ops", "email": "ops@example.com"}, license_info={ "name": "Apache 2.0", "url": "https://opensource.org/licenses/Apache-2.0", }, ) ], ) ``` Your app must use `rxe.App()` (not `rx.App()`): ```python import reflex_enterprise as rxe app = rxe.App() ``` ```md alert warning # The backend serves the API on the Reflex backend port (default `http://localhost:8000` in dev, or the `deploy_url` in production). If you're running production with `--single-port`, the API is instead reachable on the frontend port (default `http://localhost:3000`). ``` ## Authentication Every endpoint requires a Bearer token in the `Authorization` header. The token is a random UUID that identifies a **client session**: ``` Authorization: Bearer ``` All calls using the same token share state — the token plays the same role as the per-tab session cookie the browser uses. Generate one with any UUID library: ```bash TOKEN=$(python -c 'import uuid; print(uuid.uuid4())') ``` Reuse `$TOKEN` across calls if you want subsequent requests to see the effects of earlier ones (e.g. create a ticket, then list tickets). Pick a new UUID to get a fresh, independent session. ## Discovering the API The plugin publishes the OpenAPI spec at a well-known location per RFC 9727. Any compliant client can discover it from the catalog: ```bash curl http://localhost:8000/.well-known/api-catalog ``` Response (RFC 9264 Linkset): ```json { "linkset": [ { "anchor": "http://localhost:8000/", "service-desc": [ { "href": "http://localhost:8000/_reflex/events/openapi.yaml", "type": "application/vnd.oai.openapi" } ] } ] } ``` Fetch the spec directly: ```bash curl http://localhost:8000/_reflex/events/openapi.yaml ``` Browse it with any OpenAPI viewer (Swagger UI, Redoc, Scalar, the JetBrains HTTP client, etc.) pointed at that URL. ## Response shape Event handler endpoints return the state deltas produced by the handler as **newline-delimited JSON** (`application/x-ndjson`). Each line is one delta; the stream ends when the handler finishes: ``` {"state.TicketState": {"tickets": [...], "total_count": 3}} {"state.TicketState": {"open_count": 2}} ``` For one-shot clients that just want the final state, simply consume the stream to completion and then (optionally) fetch the full state: ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ http://localhost:8000/_reflex/retrieve_state ``` ```md alert info # Unlike the built-in `hydrate` event, `/_reflex/retrieve_state` does **not** reset client-storage vars (`rx.Cookie`, `rx.LocalStorage`, `rx.SessionStorage`). Use it whenever you want to read state without modifying it. ``` ## The tickets demo app The `reflex-enterprise` repository includes a ready-to-run IT-ticketing demo under `demos/tickets/` that exercises every feature of the plugin. Its `rxconfig.py` is the minimal reference setup: ```python import reflex as rx import reflex_enterprise as rxe config = rxe.Config( app_name="tickets", async_db_url="sqlite+aiosqlite:///tickets.db", db_url="sqlite:///tickets.db", plugins=[ rxe.EventHandlerAPIPlugin( contact={"name": "Reflex Maintainers", "email": "info@reflex.dev"}, license_info={ "name": "Apache 2.0", "url": "https://opensource.org/licenses/Apache-2.0", }, ) ], disable_plugins=[rx.plugins.SitemapPlugin], ) ``` The state class exposes typical CRUD handlers — `create_ticket`, `update_ticket`, `set_status`, `delete_ticket`, `seed`, `clear_all`, plus list/filter/sort/pagination helpers and a `load_tickets` on-load handler. Here's a trimmed excerpt: ```python class TicketState(rx.State): tickets: list[TicketRecord] = [] total_count: int = 0 open_count: int = 0 @rx.event async def create_ticket( self, title: str, description: str = "", priority: str = "medium", assignee: str = "", ) -> None: """Create a new IT support ticket. Args: title: Short summary of the issue. description: Optional long-form description. priority: One of "low", "medium", "high". assignee: Username of the person handling the ticket. """ await self._create_ticket_record( title=title, description=description, priority=priority, assignee=assignee, ) await self._reload_from_db() @rx.event async def set_status(self, ticket_id: str, status: str) -> None: """Set the status of a ticket. Args: ticket_id: The id of the ticket. status: One of "open", "in_progress", "closed". """ ... ``` Because the state's full name is `tickets___tickets____ticket_state`, the generated handler routes live at: ``` POST /_reflex/event/tickets___tickets____ticket_state/ ``` The state full name is built from the Python module path (dot separators become `___`) followed by the class name — inspect the generated `openapi.yaml` if you are unsure of the exact path for a given handler. ### curl examples Assume a dev server running on `http://localhost:8000` and a token in `$TOKEN`: ```bash TOKEN=$(python -c 'import uuid; print(uuid.uuid4())') BASE=http://localhost:8000 TICKET_STATE=$BASE/_reflex/event/tickets___tickets____ticket_state ``` **Discover the API.** ```bash curl $BASE/.well-known/api-catalog curl $BASE/_reflex/events/openapi.yaml ``` **Retrieve the full state dict.** ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ $BASE/_reflex/retrieve_state ``` **Seed some sample tickets.** ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ $TICKET_STATE/seed ``` **Load the first page of tickets into the session.** This mirrors the `on_load` handler the frontend runs when a browser hits `/`: ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ $TICKET_STATE/load_tickets ``` **Create a ticket.** `title` is required; `description`, `priority`, and `assignee` are optional (the server applies the same defaults as in the Python signature): ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"title":"VPN is down","priority":"high","assignee":"alice"}' \ $TICKET_STATE/create_ticket ``` **Change a ticket's status.** ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"ticket_id":"","status":"in_progress"}' \ $TICKET_STATE/set_status ``` **Partial update.** `update_ticket` treats empty strings as "leave unchanged": ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"ticket_id":"","assignee":"bob","priority":"low"}' \ $TICKET_STATE/update_ticket ``` **Delete a ticket.** ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"ticket_id":""}' \ $TICKET_STATE/delete_ticket ``` **Clear the board.** ```bash curl -X POST -H "Authorization: Bearer $TOKEN" \ $TICKET_STATE/clear_all ``` ### Example OpenAPI excerpt The generated spec groups handlers under an OpenAPI `tag` matching the state class name. Here's the entry for `create_ticket`: ```yaml /_reflex/event/tickets___tickets____ticket_state/create_ticket: post: summary: Create a new IT support ticket. description: | title: Short summary of the issue. description: Optional long-form description. priority: One of "low", "medium", "high". assignee: Username of the person handling the ticket. operationId: TicketState_create_ticket tags: [TicketState] requestBody: required: true content: application/json: schema: type: object required: [title] properties: title: {type: string} description: {type: string, default: ""} priority: {type: string, default: medium} assignee: {type: string, default: ""} responses: "200": {$ref: "#/components/responses/StreamedDelta"} "401": {$ref: "#/components/responses/Unauthorized"} ``` ## Driving the app from an LLM Because the OpenAPI spec is self-describing (summaries, parameter types, defaults, on-load references), most LLM agents with HTTP tool access can drive a Reflex app end-to-end without any extra glue code. Give them the spec URL and a natural-language task: > Use the API exposed at `http://localhost:8000/_reflex/events/openapi.yaml` to drive the application. > > Create a new ticket assigned to Masen for investigating RegistrationContext issues in reflex CI. A well-equipped agent will: 1. `GET /_reflex/events/openapi.yaml` and parse the operations. 2. Generate a session token (`uuid4`) to use as the Bearer credential. 3. Call `POST /_reflex/event/.../create_ticket` with a body like `{"title": "Investigate RegistrationContext issues in Reflex CI", "assignee": "Masen", "priority": "medium"}`. 4. Optionally call `/_reflex/retrieve_state` to confirm the ticket landed. Other prompts that work well with the tickets demo: > Using the Reflex API at `http://localhost:8000`, seed the database, then close every ticket currently assigned to `bob`. > Via `http://localhost:8000/_reflex/events/openapi.yaml`, page through every ticket and summarize which assignees have the largest open backlog. > Using the Reflex API at `http://localhost:8000`, create three high-priority tickets for the following issues, then show me the resulting state: ```md alert info # For agents that can't follow `api-catalog` automatically, point them directly at `/_reflex/events/openapi.yaml`. A single URL is enough context for most tool-using models to take it from there. ``` ## Dynamic route variables If any of your pages use dynamic route segments (e.g. `/tickets/[ticket_id]`), the plugin surfaces those as **optional query parameters** on every endpoint so the state can read them via `self.router`: ``` POST /_reflex/event/.../load_ticket_detail?ticket_id= ``` They appear under `components.parameters.route_` in the OpenAPI spec and are referenced from every operation's `parameters` list. ## Security considerations - **The Bearer token is just a session id, not an auth credential.** Anyone who can reach the backend and generate UUIDs can drive the app. Put the API behind your normal auth layer (reverse-proxy, OIDC, VPN, etc.) before exposing it outside trusted networks. - **Every event handler on every state is exposed by default.** If you have privileged handlers, either split them onto a state class you don't want to expose, or run the plugin only in environments where API access is appropriate. - **Handlers that return `rx.redirect(...)` work over the API**, but the redirect is emitted as a state delta rather than an HTTP 3xx — the client sees the URL change, not a browser redirect. This is usually what you want for programmatic clients. # Autocomplete component Source: http://localhost:3000/docs/enterprise/mantine/autocomplete.md --- title: Autocomplete --- `rxe.mantine.autocomplete` is a component for providing suggestions as the user types. It is useful for enhancing user experience by offering relevant options based on input. ```python demo exec import reflex as rx import reflex_enterprise as rxe def autocomplete_example(): return rx.vstack( rxe.mantine.autocomplete( data=["Apple", "Banana", "Cherry", "Date", "Elderberry"], placeholder="Type a fruit", label="Fruit Autocomplete", description="Select a fruit from the list", ), ) ``` # Collapse component Source: http://localhost:3000/docs/enterprise/mantine/collapse.md --- title: Collapse --- `rxe.mantine.collapse` is a component that allows you to create collapsible sections in your application. It is useful for hiding or showing content based on user interaction, such as clicking a button or a link. ```python demo exec import reflex as rx import reflex_enterprise as rxe class CollapseState(rx.State): is_open: bool = False @rx.event def toggle_collapse(self): self.is_open = not self.is_open def collapse_example(): return rx.vstack( rxe.mantine.collapse( rx.text( "This is a collapsible section. Click the button to toggle the collapse.", font_size="lg", ), in_=CollapseState.is_open, label="Collapsible Section", description="Click the button to toggle the collapse.", ), rx.button( "Toggle Collapse", on_click=lambda: CollapseState.toggle_collapse, ), ) ``` # Combobox Source: http://localhost:3000/docs/enterprise/mantine/combobox.md --- title: Combobox --- ```python exec import reflex as rx import reflex_enterprise as rxe ``` `rxe.mantine.combobox` is a wrapping of the mantine component [Combobox](https://mantine.dev/core/combobox/). It is a simple component that can be used to display a list of options, and allows the user to select one or more options from the list. It can be used in various contexts, such as in a form or as a standalone component. ```python import reflex as rx import reflex_enterprise as rxe def combobox_page(): """Combobox demo.""" return rxe.mantine.combobox( rxe.mantine.combobox.target( rx.input(type="button"), ), rxe.mantine.combobox.dropdown( rxe.mantine.combobox.options( rxe.mantine.combobox.option("Option 1"), rxe.mantine.combobox.option("Option 2"), rxe.mantine.combobox.option("Option 3"), ), ), label="Combobox", placeholder="Select a value", ) ``` # Mantine Source: http://localhost:3000/docs/enterprise/mantine.md --- title: Mantine order: 4 --- Mantine is a React component library that provides a set of high-quality components and hooks for building modern web applications. It is designed to be flexible, customizable, and easy to use, making it a popular choice among developers. Some of those components have been integrated into Reflex Enterprise, allowing you to use them in your Reflex applications. The following components are available: - JsonInput - Autocomplete - ComboBox - Multiselect - Pill - PillsInput - TagsInput - Tree - RingProgress - SemiCircleProgress - LoadingOverlay - NumberFormatter - Spoiler - Timeline - Collapse # JSON Input Source: http://localhost:3000/docs/enterprise/mantine/json-input.md --- title: JSON Input --- `rxe.mantine.json_input` is a component that allows you to input JSON data in a user-friendly way. It provides validation and formatting features to ensure that the JSON data is correctly structured. ## Example ```python demo exec import reflex as rx import reflex_enterprise as rxe class JsonInputState(rx.State): json_data: str = "" def set_json_data(self, value: str): self.json_data = value def json_input_example(): return rxe.mantine.json_input( id="json-input", value=JsonInputState.json_data, placeholder="Enter JSON data", label="JSON Input", description="Please enter valid JSON data.", required=True, size="md", format_on_blur=True, on_change=JsonInputState.set_json_data, width="300px", ) ``` # Loading Overlay component Source: http://localhost:3000/docs/enterprise/mantine/loading-overlay.md --- title: Loading Overlay --- `rxe.mantine.loading_overlay` is a component that displays a loading overlay on top of its children. It is useful for indicating that a process is ongoing and prevents user interaction with the underlying content. ```python demo exec import reflex as rx import reflex_enterprise as rxe class LoadingOverlayState(rx.State): loading: bool = False @rx.event def toggle_loading(self): self.loading = not self.loading def loading_overlay_example(): return ( rx.container( rxe.mantine.loading_overlay( rx.text( "Loading Overlay Example", height="200px", width="100px", ), overlay_props={"radius": "sm", "blur": 2}, visible=LoadingOverlayState.loading, z_index=1000, ), ), rx.button("Toggle Loading", on_click=LoadingOverlayState.toggle_loading), ) ``` # MultiSelect component Source: http://localhost:3000/docs/enterprise/mantine/multi-select.md --- title: MultiSelect --- `rxe.mantine.multi_select` is a component for selecting multiple options from a list. It allows users to choose one or more items, making it suitable for scenarios where multiple selections are required. ```python demo exec import reflex as rx import reflex_enterprise as rxe class MultiSelectState(rx.State): selected_fruits: list = [] def set_selected_fruits(self, value: list): self.selected_fruits = value def multi_select_example(): return rx.vstack( rxe.mantine.multi_select( label="Select fruits", placeholder="Pick all that you like", data=["Apple", "Banana", "Cherry", "Date", "Elderberry"], value=MultiSelectState.selected_fruits, on_change=MultiSelectState.set_selected_fruits, ) ) ``` # Number Formatter component Source: http://localhost:3000/docs/enterprise/mantine/number-formatter.md --- title: Number Formatter --- `rxe.mantine.number_formatter` is a component for formatting numbers in a user-friendly way. It allows you to specify the format, precision, and other options for displaying numbers. ```python demo exec import reflex as rx import reflex_enterprise as rxe def number_formatter_example(): return rx.vstack( rxe.mantine.number_formatter( value=100, prefix="$", ), rxe.mantine.number_formatter( value=100, suffix="€", ), rxe.mantine.number_formatter( value=1234567.89, thousand_separator=True, ), ) ``` # Pill Source: http://localhost:3000/docs/enterprise/mantine/pill.md --- title: Pill --- ```python exec import reflex as rx import reflex_enterprise as rxe ``` `rxe.mantine.pill` is a wrapping of the mantine component [Pill](https://mantine.dev/core/pill/). It is a simple component that can be used to display a small piece of information, such as a tag or a label. It can be used in various contexts, such as in a list of tags or labels, or as a standalone component. ```python demo exec import reflex as rx import reflex_enterprise as rxe def pill_page(): """Pill demo.""" return rxe.mantine.pill( "Pill", color="blue", size="md", variant="outline", radius="xl", with_remove_button=True, on_remove=lambda: rx.toast("Pill on_remove triggered"), ) ``` ## Pill Group `rxe.mantine.pill.group` allows grouping multiple `rxe.mantine.pill` components together, with a predefined layout. ```python demo exec import reflex as rx import reflex_enterprise as rxe def pill_group_page(): """Pill demo.""" return rxe.mantine.pill.group( rxe.mantine.pill("Pill 1"), rxe.mantine.pill("Pill 2"), ) ``` # PillsInput `rxe.mantine.pills_input` is a wrapping of the mantine component [PillsInput](https://mantine.dev/core/pills-input/). It is an utility component that can be used to display a list of tags or labels. It can be used in various contexts, such as in a form or as a standalone component. By itself it does not include any logic, it only renders given children. ```md alert info # For a fully functional out-of-the-box component, consider using [`rxe.mantine.tags_input`](/docs/enterprise/mantine/tags-input/) instead. ``` ## Example ```python demo exec import reflex as rx import reflex_enterprise as rxe class PillInputState(rx.State): """State for the PillsInput demo.""" tags: set[str] = {"Foo", "Bar"} @rx.event def add_tag(self, tag: str): """Add a tag to the list of tags.""" self.tags.add(tag) @rx.event def remove_tag(self, tag: str): """Remove a tag from the list of tags.""" self.tags.remove(tag) def pills_input_page(): """PillsInput demo.""" return rxe.mantine.pills_input( rxe.mantine.pill.group( rx.foreach( PillInputState.tags, lambda tag: rxe.mantine.pill( tag, with_remove_button=True, on_remove=PillInputState.remove_tag(tag), ), ), rxe.mantine.pills_input.field( placeholder="Enter tags", # on_blur=PillInputState.add_tag, ), ), label="PillsInput", id="pills-input", value=["tag1", "tag2"], ) ``` # Ring Progress component Source: http://localhost:3000/docs/enterprise/mantine/ring-progress.md --- title: Ring Progress --- `rxe.mantine.ring_progress` is a component for displaying progress in a circular format. It is useful for visualizing completion percentages or other metrics in a compact and visually appealing way. ```python demo exec import reflex as rx import reflex_enterprise as rxe import random class RingProgressState(rx.State): value: int = 50 @rx.event def random(self): self.value = random.randint(0, 100) def ring_progress_example(): return rx.vstack( rxe.mantine.ring_progress( size=100, sections=[ {"value": RingProgressState.value, "color": "blue"}, ], ), rx.button("Randomize", on_click=RingProgressState.random), ) ``` # Semi Circle Progress component Source: http://localhost:3000/docs/enterprise/mantine/semi-circle-progress.md --- title: Semi Circle Progress --- `rxe.mantine.semi_circle_progress` is a component for displaying progress in a semi-circular format. It is useful for visualizing completion percentages or other metrics in a compact and visually appealing way. ```python demo exec import reflex as rx import reflex_enterprise as rxe import random class SemiCircleProgressState(rx.State): value: int = 50 @rx.event def random(self): self.value = random.randint(0, 100) def semi_circle_progress_example(): return rx.vstack( rxe.mantine.semi_circle_progress( size=100, value=SemiCircleProgressState.value, ), rx.button("Randomize", on_click=SemiCircleProgressState.random), ) ``` # Spoiler component Source: http://localhost:3000/docs/enterprise/mantine/spoiler.md --- title: Spoiler --- `rxe.mantine.spoiler` is a component that allows you to hide or reveal content. It is useful for displaying additional information or details that may not be immediately relevant to the user. ```python demo exec import reflex as rx import reflex_enterprise as rxe def spoiler_example(): return rx.vstack( rxe.mantine.spoiler( "This is a spoiler zone where lorem ipsum text dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit...", max_height=50, show_label="Show more", hide_label="Show less", ), ) ``` # TagsInput Source: http://localhost:3000/docs/enterprise/mantine/tags-input.md --- title: TagsInput --- `rxe.mantine.tags_input` is a wrapping of the mantine component [TagsInput](https://mantine.dev/core/tags-input/). It is an utility component that can be used to display a list of tags or labels. It can be used in various contexts, such as in a form or as a standalone component. ```md alert info # You can use the props mentioned in the Mantine documentation, but they need to be passed in snake_case. ``` ## Basic Example ```python demo exec import reflex as rx import reflex_enterprise as rxe def tags_input_simple_page(): """TagsInput demo.""" return rxe.mantine.tags_input( placeholder="Enter tags", label="Press Enter to ad a tag", ) ``` ## State Example ```python demo exec import reflex as rx import reflex_enterprise as rxe class TagsInputState(rx.State): """State for the TagsInput component.""" tags: list[str] = ["Tag1", "Tag2"] @rx.event def update_tags(self, tags: list[str]): """Add a tag to the list of tags.""" self.tags = tags def tags_input_page(): """TagsInput demo.""" return rxe.mantine.tags_input( value=TagsInputState.tags, on_change=TagsInputState.update_tags, placeholder="Enter tags", label="TagsInput", description="This is a TagsInput component", error="", size="md", radius="xl", ) ``` # Timeline component Source: http://localhost:3000/docs/enterprise/mantine/timeline.md --- title: Timeline --- `rxe.mantine.timeline` is a component for displaying a sequence of events or milestones in a linear format. It is useful for visualizing progress, history, or any sequential information. ```python demo exec import reflex as rx import reflex_enterprise as rxe def timeline_example(): return rx.vstack( rxe.mantine.timeline( rxe.mantine.timeline.item( title="Step 1", bullet="•", ), rxe.mantine.timeline.item( title="Step 2", bullet="•", ), rxe.mantine.timeline.item( title="Step 3", bullet="•", ), active=1, bullet_size=24, line_width=2, color="blue", ) ) ``` # Tree component Source: http://localhost:3000/docs/enterprise/mantine/tree.md --- title: Tree --- `rxe.mantine.tree` is a component for displaying hierarchical data in a tree structure. It allows users to expand and collapse nodes, making it easy to navigate through large datasets. ```md alert warning # Due to some technical limitations(pydantic), the tree component only supports 5 levels of depths for the `data` props. ``` ```python demo exec import reflex as rx import reflex_enterprise as rxe def tree_example(): # return rx.text("Placeholder for tree example") return rxe.mantine.tree( data=[ { "value": "0", "label": "Root", "children": [ {"value": "0-1", "label": "Child 1"}, {"value": "0-2", "label": "Child 2"}, ], } ], ) ``` # Interactive Maps Source: http://localhost:3000/docs/enterprise/map.md --- title: Interactive Maps --- ```python exec import reflex as rx import reflex_enterprise as rxe ``` The map components in Reflex Enterprise provide interactive mapping capabilities built on top of **Leaflet**, one of the most popular open-source JavaScript mapping libraries. These components enable you to create rich, interactive maps with markers, layers, controls, and event handling. ```md alert info # All map components are built using Leaflet and react-leaflet, providing a familiar and powerful mapping experience. For advanced Leaflet features, refer to the [Leaflet documentation](https://leafletjs.com/reference.html). ``` 🌍 **[View Live Demo](https://map.reflex.run)** - See the map components in action with interactive examples. ## Installation & Setup Map components are included with `reflex-enterprise`. No additional installation is required. ## Basic Usage Here's a simple example of creating a map with a marker: ```python demo exec import reflex as rx import reflex_enterprise as rxe class MapState(rx.State): center: rxe.map.LatLng = rxe.map.latlng(lat=51.505, lng=-0.09) zoom: float = 13.0 def basic_map(): return rxe.map( rxe.map.tile_layer( url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution='© OpenStreetMap contributors', ), rxe.map.marker( rxe.map.popup("Hello from London!"), position=MapState.center, ), id="basic-map", center=MapState.center, zoom=MapState.zoom, height="400px", width="100%", ) ``` ## Core Components ### Map Container The `rxe.map()` component is the primary container that holds all other map elements: ```python rxe.map( # Child components (markers, layers, controls) id="my-map", center=rxe.map.latlng(lat=51.505, lng=-0.09), zoom=13, height="400px", width="100%", ) ``` **Key Properties:** - `center`: Initial map center coordinates - `zoom`: Initial zoom level (0-18+ depending on tile provider) - `bounds`: Alternative to center/zoom, fits map to bounds - `height`/`width`: Map container dimensions ### Tile Layers Tile layers provide the base map imagery. The most common is OpenStreetMap: ```python rxe.map.tile_layer( url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution="© OpenStreetMap contributors", ) ``` ### Markers Add point markers to specific locations: ```python demo exec import reflex as rx import reflex_enterprise as rxe def markers_example(): return rxe.map( rxe.map.tile_layer( url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution="© OpenStreetMap contributors", ), rxe.map.marker( rxe.map.popup( rx.vstack( rx.text("Big Ben", weight="bold"), rx.text("Famous clock tower in London"), spacing="2", ) ), position=rxe.map.latlng(lat=51.4994, lng=-0.1245), ), rxe.map.marker( rxe.map.popup("London Eye"), position=rxe.map.latlng(lat=51.5033, lng=-0.1196), ), id="markers-map", center=rxe.map.latlng(lat=51.501, lng=-0.122), zoom=14, height="400px", width="100%", ) ``` ### Vector Layers Draw shapes and areas on the map: ```python demo exec import reflex as rx import reflex_enterprise as rxe def vectors_example(): return rxe.map( rxe.map.tile_layer( url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution="© OpenStreetMap contributors", ), # Circle (radius in meters) rxe.map.circle( center=rxe.map.latlng(lat=51.505, lng=-0.09), radius=500, path_options=rxe.map.path_options( color="#ff0000", fill_color="#ff3333", fill_opacity=0.3, weight=2 ), ), # Polygon rxe.map.polygon( positions=[ rxe.map.latlng(lat=51.515, lng=-0.08), rxe.map.latlng(lat=51.515, lng=-0.07), rxe.map.latlng(lat=51.520, lng=-0.07), rxe.map.latlng(lat=51.520, lng=-0.08), ], path_options=rxe.map.path_options( color="#0000ff", fill_color="#3333ff", fill_opacity=0.3 ), ), # Polyline rxe.map.polyline( positions=[ rxe.map.latlng(lat=51.500, lng=-0.095), rxe.map.latlng(lat=51.510, lng=-0.085), rxe.map.latlng(lat=51.515, lng=-0.095), ], path_options=rxe.map.path_options(color="#00ff00", weight=4), ), id="vectors-map", center=rxe.map.latlng(lat=51.510, lng=-0.08), zoom=13, height="400px", width="100%", ) ``` ## Interactive Features ### Event Handling Maps support comprehensive event handling for user interactions: ```python demo exec import reflex as rx import reflex_enterprise as rxe class InteractiveMapState(rx.State): last_click: str = "No clicks yet" current_zoom: float = 13.0 def handle_map_click(self, event): lat = event.get("latlng", {}).get("lat", 0) lng = event.get("latlng", {}).get("lng", 0) self.last_click = f"Clicked at: {lat:.4f}, {lng:.4f}" def handle_zoom_change(self, event): self.current_zoom = float(event.get("target", {}).get("_zoom", 13.0)) def interactive_example(): return rx.vstack( rx.text(f"Last click: {InteractiveMapState.last_click}"), rx.text(f"Current zoom: {InteractiveMapState.current_zoom}"), rxe.map( rxe.map.tile_layer( url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution="© OpenStreetMap contributors", ), id="interactive-map", center=rxe.map.latlng(lat=51.505, lng=-0.09), zoom=InteractiveMapState.current_zoom, height="350px", width="100%", on_click=InteractiveMapState.handle_map_click, on_zoom=InteractiveMapState.handle_zoom_change, ), spacing="3", ) ``` ### Map Controls Add UI controls for enhanced user interaction: ```python demo exec import reflex as rx import reflex_enterprise as rxe def controls_example(): return rxe.map( rxe.map.tile_layer( url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution="© OpenStreetMap contributors", ), rxe.map.zoom_control(position="topright"), rxe.map.scale_control(position="bottomleft"), rxe.map.attribution_control(position="bottomright"), id="controls-map", center=rxe.map.latlng(lat=51.505, lng=-0.09), zoom=13, height="400px", width="100%", ) ``` ## Helper Functions ### Coordinate Creation ```python # Create latitude/longitude coordinates center = rxe.map.latlng(lat=51.505, lng=-0.09, nround=4) # Create bounds bounds = rxe.map.latlng_bounds( corner1_lat=51.49, corner1_lng=-0.11, corner2_lat=51.52, corner2_lng=-0.07 ) ``` ## Map API The Map API provides programmatic control over your maps, allowing you to manipulate the map programmatically from your Reflex state methods. ### Getting the API Reference To access the Map API, you need to get a reference to your map using its ID: ```python map_api = rxe.map.api("my-map-id") ``` ### Interactive Demo Here are some commonly used API methods demonstrated in action: ```python demo exec import reflex as rx import reflex_enterprise as rxe map_api = rxe.map.api("api-demo-map") class MapAPIState(rx.State): current_location: str = "London" def fly_to_london(self): yield map_api.fly_to([51.505, -0.09], 13) self.current_location = "London" def fly_to_paris(self): yield map_api.fly_to([48.8566, 2.3522], 13) self.current_location = "Paris" def map_api_example(): return rx.vstack( rx.text(f"Current location: {MapAPIState.current_location}"), rx.hstack( rx.button("Fly to London", on_click=MapAPIState.fly_to_london), rx.button("Fly to Paris", on_click=MapAPIState.fly_to_paris), rx.button("Zoom Out", on_click=map_api.set_zoom(8)), rx.button( "Log Center", on_click=map_api.get_center(callback=rx.console_log) ), spacing="2", ), rxe.map( rxe.map.tile_layer( url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution="© OpenStreetMap contributors", ), id="api-demo-map", center=rxe.map.latlng(lat=51.505, lng=-0.09), zoom=13.0, height="350px", width="100%", ), spacing="3", ) ``` ### Common API Methods **View Control:** - `fly_to(latlng, zoom, options)` - Smooth animated movement to location - `set_view(latlng, zoom, options)` - Instant movement to location - `set_zoom(zoom)` - Change zoom level - `zoom_in()` / `zoom_out()` - Zoom by one level - `fit_bounds(bounds, options)` - Fit map to specific bounds **Location Services:** - `locate(options)` - Get user's current location - `stop_locate()` - Stop location tracking **Information Retrieval:** - `get_center(callback)` - Get current map center - `get_zoom(callback)` - Get current zoom level - `get_bounds(callback)` - Get current map bounds - `get_size(callback)` - Get map container size **Layer Management:** - `add_layer(layer)` - Add a layer to the map - `remove_layer(layer)` - Remove a layer from the map - `has_layer(layer)` - Check if layer exists on map ### Full Leaflet API Access ```md alert info # The Map API provides access to the complete Leaflet map API. Any method available on a Leaflet map instance can be called through the MapAPI instance. Function names are automatically converted from snake_case (Python) to camelCase (JavaScript). ``` This means you can use any method from the [Leaflet Map documentation](https://leafletjs.com/reference.html#map). For example: **Python (snake_case) → JavaScript (camelCase):** - `map_api.pan_to(latlng)` → `map.panTo(latlng)` - `map_api.set_max_bounds(bounds)` → `map.setMaxBounds(bounds)` - `map_api.get_pixel_bounds()` → `map.getPixelBounds()` - `map_api.container_point_to_lat_lng(point)` → `map.containerPointToLatLng(point)` ### Advanced Example ```python demo exec import reflex as rx import reflex_enterprise as rxe class AdvancedMapState(rx.State): constraints_applied: bool = False location_tracking: bool = False location_status: str = "Location tracking disabled" def set_location_status(self, status: str): self.location_status = status def setup_map_constraints(self): map_api = rxe.map.api("advanced-demo-map") # Set maximum bounds (restrict panning to London area) max_bounds = rxe.map.latlng_bounds( corner1_lat=51.4, corner1_lng=-0.3, corner2_lat=51.6, corner2_lng=0.1 ) yield map_api.set_max_bounds(max_bounds) # Set min/max zoom levels yield map_api.set_min_zoom(10) yield map_api.set_max_zoom(16) # Disable scroll wheel zoom yield map_api.scroll_wheel_zoom(False) self.constraints_applied = True def remove_constraints(self): map_api = rxe.map.api("advanced-demo-map") # Remove bounds restriction yield map_api.set_max_bounds(None) # Reset zoom limits yield map_api.set_min_zoom(1) yield map_api.set_max_zoom(18) # Re-enable scroll wheel zoom yield map_api.scroll_wheel_zoom(True) self.constraints_applied = False def toggle_location_tracking(self): map_api = rxe.map.api("advanced-demo-map") if self.location_tracking == False: # Start location tracking locate_options = rxe.map.locate_options( set_view=True, max_zoom=16, timeout=10000, enable_high_accuracy=True, watch=False, # Single location request ) yield map_api.locate(locate_options) self.location_tracking = True self.location_status = "Requesting location..." else: # Stop location tracking yield map_api.stop_locate() self.location_tracking = False self.location_status = "Location tracking disabled" def advanced_example(): return rx.vstack( rx.hstack( rx.button( rx.cond( AdvancedMapState.constraints_applied, "Remove Constraints", "Apply Constraints", ), on_click=rx.cond( AdvancedMapState.constraints_applied, AdvancedMapState.remove_constraints, AdvancedMapState.setup_map_constraints, ), color_scheme="blue", ), rx.button( rx.cond( AdvancedMapState.location_tracking, "Disable Location", "Enable Location", ), on_click=AdvancedMapState.toggle_location_tracking, color_scheme="green", ), spacing="3", ), rx.text(f"Status: {AdvancedMapState.location_status}"), rx.text( rx.cond( AdvancedMapState.constraints_applied, "Constraints: Applied (restricted to London area, zoom 10-16, no scroll wheel)", "Constraints: None", ) ), rxe.map( rxe.map.tile_layer( url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", attribution="© OpenStreetMap contributors", ), rxe.map.marker( rxe.map.popup("Try panning and zooming when constraints are applied!"), position=rxe.map.latlng(lat=51.505, lng=-0.09), ), id="advanced-demo-map", center=rxe.map.latlng(lat=51.505, lng=-0.09), zoom=12.0, height="400px", width="100%", on_locationfound=lambda e: AdvancedMapState.set_location_status( "Location found!" ), on_locationerror=lambda e: AdvancedMapState.set_location_status( "Location error - permission denied or unavailable" ), ), spacing="3", ) ``` ### Callback Handling Many API methods that retrieve information require callbacks to handle the results: ```python class CallbackMapState(rx.State): map_info: str = "" def handle_center_result(self, result): lat = result.get("lat", 0) lng = result.get("lng", 0) self.map_info = f"Center: {lat:.4f}, {lng:.4f}" def handle_bounds_result(self, result): # result will contain bounds information self.map_info = f"Bounds: {result}" def get_map_info(self): map_api = rxe.map.api("info-map") yield map_api.get_center(self.handle_center_result) # or yield map_api.get_bounds(self.handle_bounds_result) ``` ## Available Events The map components support a comprehensive set of events: **Map Events:** - `on_click`, `on_dblclick` - Mouse click events - `on_zoom`, `on_zoom_start`, `on_zoom_end` - Zoom events - `on_move`, `on_move_start`, `on_move_end` - Pan events - `on_resize` - Map container resize - `on_load`, `on_unload` - Map lifecycle **Location Events:** - `on_locationfound`, `on_locationerror` - Geolocation **Layer Events:** - `on_layeradd`, `on_layerremove` - Layer management **Popup Events:** - `on_popupopen`, `on_popupclose` - Popup lifecycle - `on_tooltipopen`, `on_tooltipclose` - Tooltip lifecycle ## Common Patterns ### Dynamic Markers ```python class DynamicMapState(rx.State): markers: list[dict] = [ {"lat": 51.505, "lng": -0.09, "title": "London"}, {"lat": 48.8566, "lng": 2.3522, "title": "Paris"}, {"lat": 52.5200, "lng": 13.4050, "title": "Berlin"}, ] def dynamic_markers(): return rxe.map( rxe.map.tile_layer(url="..."), rx.foreach( DynamicMapState.markers, lambda marker: rxe.map.marker( rxe.map.popup(marker["title"]), position=rxe.map.latlng(lat=marker["lat"], lng=marker["lng"]), ), ), # ... map configuration ) ``` ## Best Practices 1. **Always include attribution** for tile providers 2. **Set reasonable zoom levels** (typically 1-18) 3. **Use bounds for multiple markers** instead of arbitrary center/zoom 4. **Handle loading states** for dynamic map content 5. **Optimize marker rendering** for large datasets using clustering 6. **Test on mobile devices** for touch interactions --- [← Back to main documentation](/docs/enterprise/overview/) # Reflex Enterprise Source: http://localhost:3000/docs/enterprise/overview.md --- title: Reflex Enterprise --- ```python exec import reflex as rx try: import reflex_enterprise as rxe from reflex_enterprise.components.ag_grid.resource import RendererParams except ImportError: rxe = None RendererParams = None ``` Reflex Enterprise is a package containing paid features built on top of Reflex. The full [End-User License Agreement (EULA)](https://raw.githubusercontent.com/reflex-dev/reflex/main/docs/enterprise/LICENSE) for Reflex Enterprise is published in the Reflex repository. ```md alert info # Despite being an enterprise package, free users can use the components from this package. A badge "Built with Reflex" will be shown in the bottom right corner of the app. For more information on the badge, visit [Built with Reflex](/docs/enterprise/built-with-reflex/). ``` ## Installation `reflex-enterprise` must be installed alongside `reflex` to access the enterprise features. You can install it from pypi with the following command: ```bash pip install reflex-enterprise ``` ## Features ```python exec # Create master data organized by category categories_data = [ { "category": "Configuration", "description": "Core enterprise features for deployment and branding", "count": 2, "components": [ { "feature": "show_built_with_reflex", "description": "Toggle the 'Built with Reflex' badge in your app", "cloud_tier": "Enterprise", "self_hosted_tier": "Enterprise", "link": "/docs/enterprise/built-with-reflex", }, { "feature": "use_single_port", "description": "Enable single-port deployment by proxying backend to frontend", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/single-port-proxy", }, ], }, { "category": "AGGrid and AGChart", "description": "Advanced data visualization and grid components", "count": 2, "components": [ { "feature": "AgGrid", "description": "Advanced data grid with enterprise features (sorting, filtering, grouping)", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/ag-grid", }, { "feature": "AGCharts", "description": "Interactive charts and data visualization components", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/ag-chart", }, ], }, { "category": "Interactive Components", "description": "Interactive UI features including drag-and-drop and mapping", "count": 2, "components": [ { "feature": "Drag and Drop", "description": "Drag and drop functionality for interactive UI elements", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/drag-and-drop", }, { "feature": "Mapping", "description": "Interactive maps with markers, layers, and controls", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/map", }, ], }, { "category": "Mantine", "description": "Rich UI components from Mantine library", "count": 15, "components": [ { "feature": "Autocomplete", "description": "Auto-completing text input with dropdown suggestions", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/autocomplete", }, { "feature": "Combobox", "description": "Searchable dropdown with custom options and filtering", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/combobox", }, { "feature": "Multi Select", "description": "Multi-selection dropdown with tags and search", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/multi-select", }, { "feature": "Tags Input", "description": "Input field for creating and managing tags", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/tags-input", }, { "feature": "Json Input", "description": "JSON editor with syntax highlighting and validation", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/json-input", }, { "feature": "Pill", "description": "Small rounded elements for tags, badges, and labels", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/pill", }, { "feature": "Tree", "description": "Hierarchical tree view with expandable nodes", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/tree", }, { "feature": "Timeline", "description": "Timeline component for displaying chronological events", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/timeline", }, { "feature": "Number Formatter", "description": "Format and display numbers with customizable formatting", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/number-formatter", }, { "feature": "Ring Progress", "description": "Circular progress indicator with customizable styling", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/ring-progress", }, { "feature": "Semi Circle Progress", "description": "Semi-circular progress indicator for dashboards", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/semi-circle-progress", }, { "feature": "Loading Overlay", "description": "Loading overlay with spinner for async operations", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/loading-overlay", }, { "feature": "Spoiler", "description": "Collapsible content container with show/hide toggle", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/spoiler", }, { "feature": "Collapse", "description": "Animated collapsible content with smooth transitions", "cloud_tier": "Free", "self_hosted_tier": "Free", "link": "/docs/enterprise/mantine/collapse", }, ], }, ] if rxe is not None: @rxe.arrow_func def custom_link_renderer(params: RendererParams): """Custom cell renderer for links in AG Grid.""" return rx.link( params.value, href=params.data.link, ) grid = rxe.ag_grid( column_defs=[ { "field": "category", "header_name": "Category", "cell_renderer": "agGroupCellRenderer", "suppress_menu": True, "width": 220, }, { "field": "description", "width": 500, }, { "field": "count", "header_name": "Components", "width": 150, }, ], row_data=categories_data, master_detail=True, detail_cell_renderer_params={ "detail_grid_options": { "column_defs": [ { "field": "feature", "header_name": "Component/Feature", "cell_renderer": custom_link_renderer, "width": 250, }, { "field": "description", "header_name": "Description", "width": 350, }, {"field": "cloud_tier", "header_name": "Cloud Tier", "width": 120}, { "field": "self_hosted_tier", "header_name": "Self-hosted Tier", "width": 140, }, ], "suppress_context_menu": True, "row_height": 35, }, "get_detail_row_data": lambda params: rx.vars.function.FunctionStringVar( "params.successCallback" ).call(params.data.components), }, id="features-grid", width="100%", detail_row_height=200, detail_row_auto_height=True, height="400px", loading=False, ) grid.api.set_grid_option("suppressContextMenu", True) else: grid = rx.text( "Reflex Enterprise not available. Install with: pip install reflex-enterprise" ) ``` ```python eval grid ``` ## Usage of reflex_enterprise. Using `rxe.App` as your `app` is required to use any of the components provided by the enterprise package, as well as config options provided by `rxe.Config`. ### In the main file Instead of the usual `rx.App()` to create your app, use the following: ```python import reflex_enterprise as rxe app = rxe.App() ``` ### In rxconfig.py ```python import reflex_enterprise as rxe config = rxe.Config( app_name="MyApp", ... # you can pass all rx.Config arguments as well as the one specific to rxe.Config ) ``` # Basic Flow Example Source: http://localhost:3000/docs/enterprise/react-flow/basic-flow.md This example demonstrates a simple flow diagram with three nodes and two edges, showing how nodes can be connected and how edges can be animated. ### Nodes - Input Node – starting point - Default Node – standard content node - Output Node – endpoint of the flow ### Edges - Input → Default (animated) - Default → Output ### Interactivity - Nodes can be moved - Edges update dynamically - Users can drag from handles to create new edges - Zoom, pan, and mini-map controls are available ### Visual Layout - Flow fits viewport automatically - Background grid for orientation - Light and dark color modes supported ### Example Flow ```python demo exec import reflex as rx import reflex_enterprise as rxe from reflex_enterprise.components.flow.types import Node, Edge # Common style for all nodes node_style = { "backgroundColor": "#ffcc00", "color": "#000000", "padding": "10px", "borderRadius": "5px", } class FlowState(rx.State): nodes: list[Node] = [ { "id": "1", "type": "input", "position": {"x": 100, "y": 100}, "data": {"label": "Input Node"}, "style": node_style, }, { "id": "2", "type": "default", "position": {"x": 300, "y": 200}, "data": {"label": "Default Node"}, "style": node_style, }, { "id": "3", "type": "output", "position": {"x": 500, "y": 100}, "data": {"label": "Output Node"}, "style": node_style, }, ] edges: list[Edge] = [ {"id": "e1-2", "source": "1", "target": "2", "animated": True}, {"id": "e2-3", "source": "2", "target": "3"}, ] def flow_example(): return rx.box( rxe.flow( # Core flow components rxe.flow.controls(), rxe.flow.background(), rxe.flow.mini_map(), # Flow configuration default_nodes=FlowState.nodes, default_edges=FlowState.edges, nodes=FlowState.nodes, edges=FlowState.edges, # Visual settings fit_view=True, attribution_position="bottom-right", ), height="100vh", width="100vw", ) ``` # Flow Components Source: http://localhost:3000/docs/enterprise/react-flow/components.md This page documents the main components provided by the `rxe.flow` library. ## rxe.flow.provider The `FlowProvider` component is a context provider that makes it possible to access a flow’s internal state outside of the `` component. Many of the hooks we provide rely on this component to work. **Props:** - `initial_nodes`: `Sequence[Node]` - These nodes are used to initialize the flow. They are not dynamic. - `default_edges`: `Sequence[Edge]` - These edges are used to initialize the flow. They are not dynamic. - `initial_width`: `float` - The initial width is necessary to be able to use fitView on the server. - `initial_height`: `float` - The initial height is necessary to be able to use fitView on the server. - `fit_view`: `bool` - When true, the flow will be zoomed and panned to fit all the nodes initially provided. - `initial_fit_view_options`: `FitViewOptions` - You can provide an object of options to customize the initial fitView behavior. - `initial_min_zoom`: `float` - Initial minimum zoom level. - `initial_max_zoom`: `float` - Initial maximum zoom level. - `node_origin`: `NodeOrigin` - The origin of the node to use when placing it in the flow or looking up its x and y position. - `node_extent`: `CoordinateExtent` - The boundary a node can be moved in. ## rxe.flow The `Flow` component is the main component that renders the flow. It takes in nodes and edges, and provides event handlers for user interactions. **Props:** - `nodes`: `Sequence[Node]` - An array of nodes to render in a controlled flow. - `edges`: `Sequence[Edge]` - An array of edges to render in a controlled flow. - `default_nodes`: `Sequence[Node]` - The initial nodes to render in an uncontrolled flow. - `default_edges`: `Sequence[Edge]` - The initial edges to render in an uncontrolled flow. - `node_types`: `Mapping[str, Any]` - Custom node types. - `edge_types`: `Mapping[str, Any]` - Custom edge types. - `on_nodes_change`: Event handler for when nodes change. - `on_edges_change`: Event handler for when edges change. - `on_connect`: Event handler for when a connection is made. - `fit_view`: `bool` - When true, the flow will be zoomed and panned to fit all the nodes initially provided. - `fit_view_options`: `FitViewOptions` - Options for `fit_view`. - `style`: The style of the component. ## rxe.flow.background The `Background` component renders a background for the flow. It can be a pattern of lines, dots, or a cross. **Props:** - `color`: `str` - Color of the pattern. - `bg_color`: `str` - Color of the background. - `variant`: `Literal["lines", "dots", "cross"]` - The type of pattern to render. - `gap`: `float | tuple[float, float]` - The gap between patterns. - `size`: `float` - The size of the pattern elements. **Example:** ```python rxe.flow.background(variant="dots", gap=20, size=1) ``` ## rxe.flow.controls The `Controls` component renders a panel with buttons to zoom in, zoom out, fit the view, and lock the viewport. **Props:** - `show_zoom`: `bool` - Whether to show the zoom buttons. - `show_fit_view`: `bool` - Whether to show the fit view button. - `show_interactive`: `bool` - Whether to show the lock button. - `position`: `PanelPosition` - The position of the controls on the pane. **Example:** ```python rxe.flow.controls() ``` ## rxe.flow.mini_map The `MiniMap` component renders a small overview of your flow. **Props:** - `node_color`: `str | Any` - Color of nodes on minimap. - `node_stroke_color`: `str | Any` - Stroke color of nodes on minimap. - `pannable`: `bool` - Determines whether you can pan the viewport by dragging inside the minimap. - `zoomable`: `bool` - Determines whether you can zoom the viewport by scrolling inside the minimap. - `position`: `PanelPosition` - Position of minimap on pane. **Example:** ```python rxe.flow.mini_map(pannable=True, zoomable=True) ``` # Edges Source: http://localhost:3000/docs/enterprise/react-flow/edges.md Edges connect nodes together in a flow. This page explains how to define, customize, and interact with edges in Reflex Flow. ## The Edge Type An edge is represented as a Python dictionary with the following fields: - `id` (`str`) – Unique identifier for the edge. - `source` (`str`) – ID of the source node. - `target` (`str`) – ID of the target node. - `type` (`str`) – Edge type defined in `edge_types`. - `sourceHandle` (`str | None`) – Optional source handle ID. - `targetHandle` (`str | None`) – Optional target handle ID. - `animated` (`bool`) – Whether the edge should animate. - `hidden` (`bool`) – Whether the edge is hidden. - `deletable` (`bool`) – Whether the edge can be removed. - `selectable` (`bool`) – Whether the edge can be selected. - `data` (`dict`) – Arbitrary metadata. - `label` (`Any`) – Label rendered along the edge. - `style` (`dict`) – Custom styles. - `className` (`str`) – CSS class for the edge. ## Basic Edge Types Reflex Flow comes with several built-in edge types: ### Default Edge Types ```python edges: list[Edge] = [ {"id": "e1", "source": "1", "target": "2", "type": "default"}, {"id": "e2", "source": "2", "target": "3", "type": "straight"}, {"id": "e3", "source": "3", "target": "4", "type": "step"}, {"id": "e4", "source": "4", "target": "5", "type": "smoothstep"}, {"id": "e5", "source": "5", "target": "6", "type": "bezier"}, ] ``` - **default** – Standard curved edge - **straight** – Direct line between nodes - **step** – Right-angled path with steps - **smoothstep** – Smooth right-angled path - **bezier** – Curved bezier path ## Edge Styling ### Basic Styling Add visual styling to edges using the `style` property: ```python edges: list[Edge] = [ { "id": "styled-edge", "source": "1", "target": "2", "style": { "stroke": "#ff6b6b", "strokeWidth": 3, }, } ] ``` ### Animated Edges Make edges animate with flowing dots: ```python edges: list[Edge] = [ { "id": "animated-edge", "source": "1", "target": "2", "animated": True, "style": {"stroke": "#4dabf7"}, } ] ``` ### Edge Labels Add text labels to edges: ```python edges: list[Edge] = [ { "id": "labeled-edge", "source": "1", "target": "2", "label": "Connection", "style": {"stroke": "#51cf66"}, } ] ``` # Custom Edges React Flow in Reflex also allows you to define custom edge types. This is useful when you want edges to carry extra functionality (like buttons, labels, or dynamic styling) beyond the default straight or bezier connectors. ```python demo exec import reflex as rx import reflex_enterprise as rxe from reflex_enterprise.components.flow.types import ( ConnectionInProgress, Edge, NoConnection, Node, Position, ) class SimpleEdgeDemoState(rx.State): nodes: list[Node] = [ { "id": "1", "position": {"x": 0, "y": 0}, "data": {"label": "Node A"}, "style": { "color": "#000000", }, }, { "id": "2", "position": {"x": 250, "y": 150}, "data": {"label": "Node B"}, "style": { "color": "#000000", }, }, ] edges: list[Edge] = [{"id": "e1-2", "source": "1", "target": "2", "type": "button"}] @rx.event def set_nodes(self, nodes: list[Node]): self.nodes = nodes @rx.event def set_edges(self, edges: list[Edge]): self.edges = edges @rx.event def handle_connect_end( self, connection_status: NoConnection | ConnectionInProgress, ): if not connection_status["isValid"]: new_edge = { "id": f"{connection_status['fromNode']['id']}-{connection_status['toNode']['id']}", "source": connection_status["fromNode"]["id"], "target": connection_status["toNode"]["id"], "type": "button", } self.edges.append(new_edge) @rx.memo def button_edge( id: rx.Var[str], sourceX: rx.Var[float], sourceY: rx.Var[float], targetX: rx.Var[float], targetY: rx.Var[float], sourcePosition: rx.Var[Position], targetPosition: rx.Var[Position], markerEnd: rx.Var[str], ): bezier_path = rxe.components.flow.util.get_bezier_path( source_x=sourceX, source_y=sourceY, target_x=targetX, target_y=targetY, source_position=sourcePosition, target_position=targetPosition, ) mid_x = bezier_path.label_x mid_y = bezier_path.label_y return rx.fragment( rxe.flow.base_edge(path=bezier_path.path, markerEnd=markerEnd), rxe.flow.edge_label_renderer( rx.el.div( rx.el.button( "×", class_name=( "w-[30px] h-[30px] border-2 border-gray-200 bg-gray-200 text-black rounded-full text-[12px] pt-0 cursor-pointer hover:bg-gray-400 hover:text-white" ), on_click=rx.run_script( rxe.flow.api.set_edges( rx.vars.FunctionStringVar.create( "Array.prototype.filter.call" ).call( rxe.flow.api.get_edges(), rx.Var(f"((edge) => edge.id !== {id})"), ), ) ), style={ "position": "absolute", "left": f"{mid_x}px", "top": f"{mid_y}px", "transform": "translate(-50%, -50%)", "pointerEvents": "all", }, ), ) ), ) def very_simple_custom_edge_example(): return rx.box( rxe.flow( rxe.flow.background(), default_nodes=SimpleEdgeDemoState.nodes, default_edges=SimpleEdgeDemoState.edges, nodes=SimpleEdgeDemoState.nodes, edges=SimpleEdgeDemoState.edges, on_connect=lambda connection: SimpleEdgeDemoState.set_edges( rxe.flow.util.add_edge(connection, SimpleEdgeDemoState.edges) ), on_connect_end=lambda status, event: SimpleEdgeDemoState.handle_connect_end( status ), edge_types={"button": button_edge}, fit_view=True, ), height="100vh", width="100%", ) ``` # Example React Flow Components Source: http://localhost:3000/docs/enterprise/react-flow/examples.md This section showcases examples of interactive flow components built with Reflex and Reflex Enterprise. Learn how to create dynamic nodes, edges, and custom behaviors for building flow diagrams in your React apps. ## Add Node on Edge Drop In this example, we demonstrate how to dynamically add nodes to a flow when a connection is dropped onto the canvas. When the user drops a connection, a new node is created at the drop point, and an edge is added between the source node and the new node. ```python demo exec import reflex as rx import reflex_enterprise as rxe from reflex_enterprise.components.flow.types import ( ConnectionInProgress, Edge, NoConnection, Node, XYPosition, ) node_style = { "color": "#000000", } initial_nodes: list[Node] = [ { "id": "0", "type": "input", "data": {"label": "Node"}, "position": {"x": 0, "y": 50}, "style": node_style, }, ] class AddNodesOnEdgeDropState(rx.State): nodes: rx.Field[list[Node]] = rx.field(default_factory=lambda: initial_nodes) edges: rx.Field[list[Edge]] = rx.field(default_factory=list) node_id: int = 1 @rx.event def increment(self): self.node_id += 1 @rx.event def set_nodes(self, nodes: list[Node]): self.nodes = nodes @rx.event def set_edges(self, edges: list[Edge]): self.edges = edges @rx.event def handle_connect_end( self, connection_status: NoConnection | ConnectionInProgress, event: rx.event.PointerEventInfo, flow_position: XYPosition, ): if not connection_status["isValid"]: node_id = str(self.node_id) self.increment() self.nodes.append({ "id": node_id, "position": flow_position, "data": {"label": f"Node {node_id}"}, "origin": (0.5, 0.0), "style": node_style, }) self.edges.append({ "id": node_id, "source": connection_status["fromNode"]["id"], "target": node_id, "style": node_style, }) def add_node_on_edge_drop(): return rx.box( rxe.flow.provider( rxe.flow( rxe.flow.controls(), rxe.flow.mini_map(), rxe.flow.background(), on_connect=lambda connection: AddNodesOnEdgeDropState.set_edges( rxe.flow.util.add_edge(connection, AddNodesOnEdgeDropState.edges) ), on_connect_end=( lambda connection_status, event: ( AddNodesOnEdgeDropState.handle_connect_end( connection_status, event, rxe.flow.api.screen_to_flow_position( x=event.client_x, y=event.client_y, ), ) ) ), nodes=AddNodesOnEdgeDropState.nodes, edges=AddNodesOnEdgeDropState.edges, default_nodes=AddNodesOnEdgeDropState.nodes, default_edges=AddNodesOnEdgeDropState.edges, on_nodes_change=lambda changes: AddNodesOnEdgeDropState.set_nodes( rxe.flow.util.apply_node_changes( AddNodesOnEdgeDropState.nodes, changes ) ), on_edges_change=lambda changes: AddNodesOnEdgeDropState.set_edges( rxe.flow.util.apply_edge_changes( AddNodesOnEdgeDropState.edges, changes ) ), fit_view=True, fit_view_options={"padding": 2}, node_origin=(0.5, 0.0), ) ), height="100vh", width="100vw", ) ``` ## Connection Limit on Custom Node This example demonstrates how to create a custom node with a connection limit on its handle. The handle can be configured to allow a specific number of connections, or no connections at all, using the isConnectable property. This is useful when you want to restrict the number of connections a node can have. ```python demo exec import reflex as rx import reflex_enterprise as rxe from reflex_enterprise.components.flow.types import Edge, HandleType, Node, Position node_style = { "color": "#000000", } class ConnectionLimitState(rx.State): nodes: rx.Field[list[Node]] = rx.field( default_factory=lambda: [ { "id": "1", "type": "input", "data": {"label": "Node 1"}, "position": {"x": 0, "y": 25}, "sourcePosition": "right", "style": node_style, }, { "id": "2", "type": "custom", "data": {}, "position": {"x": 250, "y": 50}, "style": node_style, }, { "id": "3", "type": "input", "data": {"label": "Node 2"}, "position": {"x": 0, "y": 100}, "sourcePosition": "right", "style": node_style, }, ] ) edges: rx.Field[list[Edge]] = rx.field(default_factory=list) @rx.event def set_nodes(self, nodes: list[Node]): self.nodes = nodes @rx.event def set_edges(self, edges: list[Edge]): self.edges = edges @rx.memo def custom_handle( type: rx.Var[HandleType], position: rx.Var[Position], connection_count: rx.Var[int] ): connections = rxe.flow.api.get_node_connections() return rxe.flow.handle( type=type, position=position, connection_count=connection_count, is_connectable=connections.length() < connection_count.guess_type(), ) @rx.memo def custom_node(): return rx.el.div( custom_handle(type="target", position="left", connection_count=1), rx.el.div("← Only one edge allowed"), class_name="border border-1 p-2 rounded-sm", border_color=rx.color_mode_cond("black", ""), color="black", bg="white", ) def connection_limit(): return rx.box( rxe.flow( rxe.flow.background(), nodes=ConnectionLimitState.nodes, edges=ConnectionLimitState.edges, default_nodes=ConnectionLimitState.nodes, default_edges=ConnectionLimitState.edges, on_nodes_change=lambda changes: ConnectionLimitState.set_nodes( rxe.flow.util.apply_node_changes(ConnectionLimitState.nodes, changes) ), on_edges_change=lambda changes: ConnectionLimitState.set_edges( rxe.flow.util.apply_edge_changes(ConnectionLimitState.edges, changes) ), on_connect=lambda connection: ConnectionLimitState.set_edges( rxe.flow.util.add_edge(connection, ConnectionLimitState.edges) ), node_types={ "custom": rx.vars.function.ArgsFunctionOperation.create( (), custom_node() ) }, color_mode="light", fit_view=True, ), height="100vh", width="100vw", ) ``` # Hooks (API) Source: http://localhost:3000/docs/enterprise/react-flow/hooks.md The `rxe.flow.api` module provides hooks to interact with the Flow instance. These hooks are wrappers around the `useReactFlow` hook from React Flow. ## Node Hooks - `get_nodes()`: Returns an array of all nodes in the flow. - `set_nodes(nodes)`: Sets the nodes in the flow. - `add_nodes(nodes)`: Adds nodes to the flow. - `get_node(id)`: Returns a node by its ID. - `update_node(id, node_update, replace=False)`: Updates a node in the flow. - `update_node_data(id, data_update, replace=False)`: Updates a node's data in the flow. ## Edge Hooks - `get_edges()`: Returns an array of all edges in the flow. - `set_edges(edges)`: Sets the edges in the flow. - `add_edges(edges)`: Adds edges to the flow. - `get_edge(id)`: Returns an edge by its ID. - `update_edge(id, edge_update, replace=False)`: Updates an edge in the flow. - `update_edge_data(id, data_update, replace=False)`: Updates an edge's data in the flow. ## Viewport Hooks - `screen_to_flow_position(x, y, snap_to_grid=False)`: Translates a screen pixel position to a flow position. - `flow_to_screen_position(x, y)`: Translates a position inside the flow’s canvas to a screen pixel position. ## Other Hooks - `to_object()`: Converts the React Flow state to a JSON object. - `get_intersecting_nodes(node, partially=True, nodes=None)`: Find all the nodes currently intersecting with a given node or rectangle. - `get_node_connections(id=None, handle_type=None, handle_id=None)`: This hook returns an array of connections on a specific node, handle type ("source", "target") or handle ID. - `get_connection()`: Returns the current connection state when there is an active connection interaction. # Adding Interactivity to Your Flow Source: http://localhost:3000/docs/enterprise/react-flow/interactivity.md This guide shows how to create an interactive flow in Reflex, allowing you to select, drag, and connect nodes and edges. ## Define the State We start by defining the nodes and edges of the flow. The `FlowState` class holds the nodes and edges as state variables and includes event handlers to respond to changes. ```python import reflex as rx import reflex_enterprise as rxe from reflex_enterprise.components.flow.types import Node, Edge class FlowState(rx.State): nodes: list[Node] = [ { "id": "1", "type": "input", "position": {"x": 100, "y": 100}, "data": {"label": "Node 1"}, }, { "id": "2", "type": "default", "position": {"x": 300, "y": 200}, "data": {"label": "Node 2"}, }, ] edges: list[Edge] = [ { "id": "e1-2", "source": "1", "target": "2", "label": "Connection", "type": "step", } ] ``` # Add Event Handlers Event handlers allow the flow to respond to user interactions such as dragging nodes, updating edges, or creating new connections. ```python @rx.event def set_nodes(self, nodes: list[Node]): self.nodes = nodes @rx.event def set_edges(self, edges: list[Edge]): self.edges = edges ``` - set_nodes updates nodes when they are moved or edited. - set_edges updates edges when they are modified or deleted. ## Render the Interactive Flow Finally, we render the flow using **rxe.flow**, passing in the state and event handlers. Additional UI features include zoom/pan controls, a background grid, and a mini-map for navigation. ```python def interactive_flow(): return rx.box( rxe.flow( rxe.flow.controls(), rxe.flow.background(), rxe.flow.mini_map(), nodes=FlowState.nodes, edges=FlowState.edges, on_nodes_change=lambda node_changes: FlowState.set_nodes( rxe.flow.util.apply_node_changes(FlowState.nodes, node_changes) ), on_edges_change=lambda edge_changes: FlowState.set_edges( rxe.flow.util.apply_edge_changes(FlowState.edges, edge_changes) ), fit_view=True, attribution_position="bottom-right", ), height="100vh", width="100vw", ) ``` # Nodes Source: http://localhost:3000/docs/enterprise/react-flow/nodes.md Nodes are the fundamental building blocks of a flow. This page explains how to define and customize nodes in Reflex Flow. ## The Node Type A node is represented as a Python dictionary with the following fields: - `id` (`str`) – Unique identifier for the node. - `position` (`dict`) – Position of the node with `x` and `y` coordinates. - `data` (`dict`) – Arbitrary data passed to the node component. - `type` (`str`) – Node type defined in `node_types`. - `sourcePosition` (`str`) – Controls source handle position ("top", "right", "bottom", "left"). - `targetPosition` (`str`) – Controls target handle position ("top", "right", "bottom", "left"). - `hidden` (`bool`) – Whether the node is visible on the canvas. - `selected` (`bool`) – Whether the node is currently selected. - `draggable` (`bool`) – Whether the node can be dragged. - `selectable` (`bool`) – Whether the node can be selected. - `connectable` (`bool`) – Whether the node can be connected to other nodes. - `deletable` (`bool`) – Whether the node can be deleted. - `width` (`float`) – Width of the node. - `height` (`float`) – Height of the node. - `parentId` (`str`) – Parent node ID for creating sub-flows. - `style` (`dict`) – Custom styles for the node. - `className` (`str`) – CSS class name for the node. ## Built-in Node Types Reflex Flow includes several built-in node types: ```python nodes: list[Node] = [ { "id": "1", "type": "input", "position": {"x": 100, "y": 100}, "data": {"label": "Start"}, }, { "id": "2", "type": "default", "position": {"x": 300, "y": 100}, "data": {"label": "Process"}, }, { "id": "3", "type": "output", "position": {"x": 500, "y": 100}, "data": {"label": "End"}, }, ] ``` - **input** – Entry point with only source handles - **default** – Standard node with both source and target handles - **output** – Exit point with only target handles ## Basic Node Configuration ### Node Positioning ```python node = { "id": "positioned-node", "type": "default", "position": {"x": 250, "y": 150}, "data": {"label": "Positioned Node"}, } ``` ### Node Styling ```python styled_node = { "id": "styled-node", "type": "default", "position": {"x": 100, "y": 200}, "data": {"label": "Custom Style"}, "style": { "background": "#ff6b6b", "color": "white", "border": "2px solid #ff5252", "borderRadius": "8px", "padding": "10px", }, } ``` ### Handle Positioning ```python node_with_handles = { "id": "handle-node", "type": "default", "position": {"x": 300, "y": 300}, "data": {"label": "Custom Handles"}, "sourcePosition": "right", "targetPosition": "left", } ``` # Custom Nodes Creating custom nodes is as easy as building a regular React component and passing it to the `node_types`. Since they’re standard React components, you can display any content and implement any functionality you need. Plus, you’ll have access to a range of props that allow you to extend and customize the default node behavior. Below is an example custom node using a `color picker` component. ```python demo exec from typing import Any import reflex as rx import reflex_enterprise as rxe from reflex_enterprise.components.flow.types import Connection, Edge, Node class CustomNodeState(rx.State): bg_color: rx.Field[str] = rx.field(default="#c9f1dd") nodes: rx.Field[list[Node]] = rx.field( default_factory=lambda: [ { "id": "1", "type": "input", "data": {"label": "An input node"}, "position": {"x": 0, "y": 50}, "sourcePosition": "right", "style": { "color": "#000000", }, }, { "id": "2", "type": "selectorNode", "data": { "color": "#c9f1dd", }, "position": {"x": 300, "y": 50}, }, { "id": "3", "type": "output", "data": {"label": "Output A"}, "position": {"x": 650, "y": 25}, "targetPosition": "left", "style": { "color": "#000000", }, }, { "id": "4", "type": "output", "data": {"label": "Output B"}, "position": {"x": 650, "y": 100}, "targetPosition": "left", "style": { "color": "#000000", }, }, ] ) edges: rx.Field[list[Edge]] = rx.field( default_factory=lambda: [ { "id": "e1-2", "source": "1", "target": "2", "animated": True, }, { "id": "e2a-3", "source": "2", "target": "3", "animated": True, }, { "id": "e2b-4", "source": "2", "target": "4", "animated": True, }, ] ) @rx.event def on_change_color(self, color: str): self.nodes = [ node if node["id"] != "2" or "data" not in node else {**node, "data": {**node["data"], "color": color}} for node in self.nodes ] self.bg_color = color @rx.event def set_nodes(self, nodes: list[Node]): self.nodes = nodes @rx.event def set_edges(self, edges: list[Edge]): self.edges = edges @rx.memo def color_selector_node(data: rx.Var[dict], isConnectable: rx.Var[bool]): data = data.to(dict) return rx.el.div( rxe.flow.handle( type="target", position="left", is_connectable=isConnectable, ), rx.el.div( "Custom Color Picker Node: ", rx.el.strong(data["color"]), ), rx.el.input( class_name="nodrag", type="color", on_change=CustomNodeState.on_change_color, default_value=data["color"], ), rxe.flow.handle( type="source", position="right", is_connectable=isConnectable, ), class_name="border border-1 p-2 rounded-sm", border_color=rx.color_mode_cond("black", ""), color="black", bg="white", ) def node_stroke_color(node: rx.vars.ObjectVar[Node]): return rx.match( node["type"], ("input", "#0041d0"), ( "selectorNode", CustomNodeState.bg_color, ), ("output", "#ff0072"), None, ) def node_color(node: rx.vars.ObjectVar[Node]): return rx.match( node["type"], ( "selectorNode", CustomNodeState.bg_color, ), "#fff", ) def custom_node(): return rx.box( rxe.flow( rxe.flow.background(bg_color=CustomNodeState.bg_color), rxe.flow.mini_map( node_stroke_color=rx.vars.function.ArgsFunctionOperation.create( ("node",), node_stroke_color(rx.Var("node").to(Node)) ), node_color=rx.vars.function.ArgsFunctionOperation.create( ("node",), node_color(rx.Var("node").to(Node)) ), ), rxe.flow.controls(), default_nodes=CustomNodeState.nodes, default_edges=CustomNodeState.edges, nodes=CustomNodeState.nodes, edges=CustomNodeState.edges, on_nodes_change=lambda changes: CustomNodeState.set_nodes( rxe.flow.util.apply_node_changes(CustomNodeState.nodes, changes) ), on_edges_change=lambda changes: CustomNodeState.set_edges( rxe.flow.util.apply_edge_changes(CustomNodeState.edges, changes) ), on_connect=lambda connection: CustomNodeState.set_edges( rxe.flow.util.add_edge( connection.to(dict).merge({"animated": True}).to(Connection), CustomNodeState.edges, ) ), node_types={"selectorNode": color_selector_node}, color_mode="light", snap_grid=(20, 20), default_viewport={"x": 0, "y": 0, "zoom": 1.5}, snap_to_grid=True, attribution_position="bottom-left", fit_view=True, ), height="100vh", width="100vw", ) ``` # Overview Source: http://localhost:3000/docs/enterprise/react-flow/overview.md At its core, a flow diagram is an interactive graph composed of nodes connected by edges. To help understand the key concepts, let’s go over the main components of a flow. ### Nodes Nodes are the building blocks of a flow. While there are a few default node types available, the real power comes from customizing them. You can design nodes to include interactive elements, display dynamic data, or support multiple connection points. The framework provides the foundation—you provide the functionality and style. ### Handles Handles are the points on a node where edges attach. They typically appear on the top, bottom, left, or right sides of a node, but can be positioned and styled freely. Nodes can have multiple handles, allowing for complex connection setups. ### Edges Edges are the connections between nodes. Each edge requires a source node and a target node. Edges can be styled and customized, and nodes with multiple handles can support multiple edges. Custom edges can include interactive elements, specialized routing, or unique visual styles beyond simple lines. ### Connection Line When creating a new edge, you can click and drag from one handle to another. While dragging, the placeholder edge is called a connection line. Connection lines behave like edges and can be customized in appearance and behavior. ### Viewport The viewport is the visible area containing the flow. Each node has x- and y-coordinates representing its position. Moving the viewport changes these coordinates, and zooming in or out adjusts the zoom level. The viewport ensures the diagram remains navigable and interactive. # Theming Source: http://localhost:3000/docs/enterprise/react-flow/theming.md You can customize the appearance of the Flow component using CSS. The Flow component comes with a default theme, which you can override with your own styles. ## CSS Variables The Flow component uses CSS variables for theming. You can override these variables to change the appearance of the flow. Here are some of the most common variables: ```css .react-flow { --xy-background-color: #f7f9fb; --xy-node-border-default: 1px solid #ededed; --xy-node-boxshadow-default: 0px 3.54px 4.55px 0px #00000005, 0px 3.54px 4.55px 0px #0000000d, 0px 0.51px 1.01px 0px #0000001a; --xy-node-border-radius-default: 8px; --xy-handle-background-color-default: #ffffff; --xy-handle-border-color-default: #aaaaaa; --xy-edge-label-color-default: #505050; } ``` ## Custom Stylesheets You can add custom stylesheets to your app to override the default styles. To do this, add the `stylesheets` prop to your `rxe.App` or `rx.App` instance: ```python app = rxe.App( stylesheets=[ "/css/my-custom-styles.css", ], ) ``` Then, create a file `assets/css/my-custom-styles.css` in your project and add your custom styles there. ## Customizing Node and Edge Styles You can also apply custom styles to individual nodes and edges using the `style` and `className` props. ### Using the style prop You can pass a style dictionary to the `style` prop of a node or edge: ```python node = { "id": "1", "position": {"x": 100, "y": 100}, "data": {"label": "Node 1"}, "style": {"backgroundColor": "#ffcc00"}, } ``` ### Using the className prop You can also pass a class name to the `className` prop and define the styles in your CSS file: ```python # In your python code node = { "id": "1", "position": {"x": 100, "y": 100}, "data": {"label": "Node 1"}, "className": "my-custom-node", } ``` ```css /* In your CSS file */ .my-custom-node { background-color: #ffcc00; border: 2px solid #ff9900; border-radius: 10px; } ``` # Utility Functions Source: http://localhost:3000/docs/enterprise/react-flow/utils.md The `rxe.flow.util` module provides utility functions for working with Flow components. ## Path Utilities These functions are used to calculate the path for an edge. - `get_simple_bezier_path(source_x, source_y, target_x, target_y, source_position="bottom", target_position="top")`: Returns everything you need to render a simple bezier edge between two nodes. - `get_bezier_path(source_x, source_y, target_x, target_y, source_position="bottom", target_position="top", curvature=0.5)`: Returns everything you need to render a bezier edge between two nodes. - `get_straight_path(source_x, source_y, target_x, target_y)`: Calculates the straight line path between two points. - `get_smooth_step_path(source_x, source_y, target_x, target_y, source_position="bottom", target_position="top", border_radius=5, center_x=None, center_y=None, offset=20, step_position=0.5)`: Returns everything you need to render a stepped path between two nodes. ## Change Handlers These functions are used to apply changes to nodes and edges from the `on_nodes_change` and `on_edges_change` event handlers. - `apply_node_changes(nodes, changes)`: Applies changes to nodes in the flow. - `apply_edge_changes(edges, changes)`: Applies changes to edges in the flow. ## Edge and Connection Utilities - `add_edge(params, edges)`: Creates a new edge in the flow. ## Graph Utilities - `get_incomers(node_id, nodes, edges)`: Returns all incoming nodes connected to the given node. - `get_outgoers(node_id, nodes, edges)`: Returns all outgoing nodes connected to the given node. - `get_connected_edges(nodes, edges)`: Returns all edges connected to the given nodes. # Single Port Proxy Source: http://localhost:3000/docs/enterprise/single-port-proxy.md Enable single-port deployment by proxying the backend to the frontend port. ## Configuration ```python import reflex_enterprise as rxe config = rxe.Config( use_single_port=True, ) ``` This allows your application to run on a single port, which is useful for deployment scenarios where you can only expose one port. # Background Tasks Source: http://localhost:3000/docs/events/background-events.md ```python exec import reflex as rx ``` A background task is a special type of `EventHandler` that may run concurrently with other `EventHandler` functions. This enables long-running tasks to execute without blocking UI interactivity. A background task is defined by decorating an async `State` method with `@rx.event(background=True)`. ```md alert warning # `@rx.event(background=True)` used to be called `@rx.background`. In Reflex version 0.6.5 and later, the `@rx.background` decorator has been renamed to `@rx.event(background=True)`. ``` Whenever a background task needs to interact with the state, **it must enter an `async with self` context block** which refreshes the state and takes an exclusive lock to prevent other tasks or event handlers from modifying it concurrently. Because other `EventHandler` functions may modify state while the task is running, **outside of the context block, Vars accessed by the background task may be _stale_**. Attempting to modify the state from a background task outside of the context block will raise an `ImmutableStateError` exception. In the following example, the `my_task` event handler is decorated with `@rx.event(background=True)` and increments the `counter` variable every half second, as long as certain conditions are met. While it is running, the UI remains interactive and continues to process events normally. ```md alert info # Background events are similar to simple Task Queues like [Celery](https://www.fullstackpython.com/celery.html) allowing asynchronous events. ``` ```python demo exec id=background_demo import asyncio import reflex as rx class MyTaskState(rx.State): counter: int = 0 max_counter: int = 10 running: bool = False _n_tasks: int = 0 @rx.event def set_max_counter(self, value: str): self.max_counter = int(value) @rx.event(background=True) async def my_task(self): async with self: # The latest state values are always available inside the context if self._n_tasks > 0: # only allow 1 concurrent task return # State mutation is only allowed inside context block self._n_tasks += 1 while True: async with self: # Check for stopping conditions inside context if self.counter >= self.max_counter: self.running = False if not self.running: self._n_tasks -= 1 return self.counter += 1 # Await long operations outside the context to avoid blocking UI await asyncio.sleep(0.5) @rx.event def toggle_running(self): self.running = not self.running if self.running: return MyTaskState.my_task @rx.event def clear_counter(self): self.counter = 0 def background_task_example(): return rx.hstack( rx.heading(MyTaskState.counter, " /"), rx.input( value=MyTaskState.max_counter, on_change=MyTaskState.set_max_counter, width="8em", ), rx.button( rx.cond(~MyTaskState.running, "Start", "Stop"), on_click=MyTaskState.toggle_running, ), rx.button( "Reset", on_click=MyTaskState.clear_counter, ), ) ``` ## Terminating Background Tasks on Page Close or Navigation Sometimes, background tasks may continue running even after the user navigates away from the page or closes the browser tab. To handle such cases, you can check if the websocket associated with the state is disconnected and terminate the background task when necessary. The solution involves checking if the client_token is still valid in the app.event_namespace.token_to_sid mapping. If the session is lost (e.g., the user navigates away or closes the page), the background task will stop. ```python import asyncio import reflex as rx class State(rx.State): @rx.event(background=True) async def loop_function(self): while True: if self.router.session.client_token not in app.event_namespace.token_to_sid: print( "WebSocket connection closed or user navigated away. Stopping background task." ) break print("Running background task...") await asyncio.sleep(2) @rx.page(on_load=State.loop_function) def index(): return rx.text( "Hello, this page will manage background tasks and stop them when the page is closed or navigated away." ) ``` ## Task Lifecycle When a background task is triggered, it starts immediately, saving a reference to the task in `app.background_tasks`. When the task completes, it is removed from the set. Multiple instances of the same background task may run concurrently, and the framework makes no attempt to avoid duplicate tasks from starting. It is up to the developer to ensure that duplicate tasks are not created under the circumstances that are undesirable. In the example above, the `_n_tasks` backend var is used to control whether `my_task` will enter the increment loop, or exit early. ## Background Task Limitations Background tasks mostly work like normal `EventHandler` methods, with certain exceptions: - Background tasks must be `async` functions. - Background tasks cannot modify the state outside of an `async with self` context block. - Background tasks may read the state outside of an `async with self` context block, but the value may be stale. - Background tasks may not be directly called from other event handlers or background tasks. Instead use `yield` or `return` to trigger the background task. # Chaining events Source: http://localhost:3000/docs/events/chaining-events.md ```python exec import reflex as rx ``` ## Calling Event Handlers From Event Handlers You can call other event handlers from event handlers to keep your code modular. Just use the `self.call_handler` syntax to run another event handler. As always, you can yield within your function to send incremental updates to the frontend. ```python demo exec id=call-handler import asyncio class CallHandlerState(rx.State): count: int = 0 progress: int = 0 @rx.event async def run(self): # Reset the count. self.set_progress(0) yield # Count to 10 while showing progress. for i in range(10): # Wait and increment. await asyncio.sleep(0.5) self.count += 1 # Update the progress. self.set_progress(i + 1) # Yield to send the update. yield def call_handler_example(): return rx.vstack( rx.badge(CallHandlerState.count, font_size="1.5em", color_scheme="green"), rx.progress(value=CallHandlerState.progress, max=10, width="100%"), rx.button("Run", on_click=CallHandlerState.run), ) ``` ## Returning Events From Event Handlers So far, we have only seen events that are triggered by components. However, an event handler can also return events. In Reflex, event handlers run synchronously, so only one event handler can run at a time, and the events in the queue will be blocked until the current event handler finishes.The difference between returning an event and calling an event handler is that returning an event will send the event to the frontend and unblock the queue. ```md alert info # Be sure to use the class name `State` (or any substate) rather than `self` when returning events. ``` Try entering an integer in the input below then clicking out. ```python demo exec id=collatz class CollatzState(rx.State): count: int = 1 @rx.event def start_collatz(self, count: str): """Run the collatz conjecture on the given number.""" self.count = abs(int(count if count else 1)) return CollatzState.run_step @rx.event async def run_step(self): """Run a single step of the collatz conjecture.""" while self.count > 1: await asyncio.sleep(0.5) if self.count % 2 == 0: # If the number is even, divide by 2. self.count //= 2 else: # If the number is odd, multiply by 3 and add 1. self.count = self.count * 3 + 1 yield def collatz_example(): return rx.vstack( rx.badge(CollatzState.count, font_size="1.5em", color_scheme="green"), rx.input(on_blur=CollatzState.start_collatz), ) ``` In this example, we run the [Collatz Conjecture](https://en.wikipedia.org/wiki/Collatz_conjecture) on a number entered by the user. When the `on_blur` event is triggered, the event handler `start_collatz` is called. It sets the initial count, then calls `run_step` which runs until the count reaches `1`. # Decentralized Event Handlers Source: http://localhost:3000/docs/events/decentralized-event-handlers.md ```python exec import reflex as rx ``` ## Overview Decentralized event handlers allow you to define event handlers outside of state classes, providing more flexible code organization. This feature was introduced in Reflex v0.7.10 and enables a more modular approach to event handling. With decentralized event handlers, you can: - Organize event handlers by feature rather than by state class - Separate UI logic from state management - Create more maintainable and scalable applications ## Basic Usage To create a decentralized event handler, use the `@rx.event` decorator on a function that takes a state instance as its first parameter: ```python demo exec import reflex as rx class MyState(rx.State): count: int = 0 @rx.event def increment(state: MyState, amount: int): state.count += amount def decentralized_event_example(): return rx.vstack( rx.heading(f"Count: {MyState.count}"), rx.hstack( rx.button("Increment by 1", on_click=increment(1)), rx.button("Increment by 5", on_click=increment(5)), rx.button("Increment by 10", on_click=increment(10)), ), spacing="4", align="center", ) ``` In this example: 1. We define a `MyState` class with a `count` variable 2. We create a decentralized event handler `increment` that takes a `MyState` instance as its first parameter 3. We use the event handler in buttons, passing different amounts to increment by ## Compared to Traditional Event Handlers Here's a comparison between traditional event handlers defined within state classes and decentralized event handlers: ```python box # Traditional event handler within a state class class TraditionalState(rx.State): count: int = 0 @rx.event def increment(self, amount: int = 1): self.count += amount # Usage in components rx.button("Increment", on_click=TraditionalState.increment(5)) # Decentralized event handler outside the state class class DecentralizedState(rx.State): count: int = 0 @rx.event def increment(state: DecentralizedState, amount: int = 1): state.count += amount # Usage in components rx.button("Increment", on_click=increment(5)) ``` Key differences: - Traditional event handlers use `self` to reference the state instance - Decentralized event handlers explicitly take a state instance as the first parameter - Both approaches use the same syntax for triggering events in components - Both can be decorated with `@rx.event` respectively ## Best Practices ### When to Use Decentralized Event Handlers Decentralized event handlers are particularly useful in these scenarios: 1. **Large applications** with many event handlers that benefit from better organization 2. **Feature-based organization** where you want to group related event handlers together 3. **Separation of concerns** when you want to keep state definitions clean and focused ### Type Annotations Always use proper type annotations for your state parameter and any additional parameters: ```python box @rx.event def update_user(state: UserState, name: str, age: int): state.name = name state.age = age ``` ### Naming Conventions Follow these naming conventions for clarity: 1. Use descriptive names that indicate the action being performed 2. Use the state class name as the type annotation for the first parameter 3. Name the state parameter consistently across your codebase (e.g., always use `state` or the first letter of the state class) ### Organization Consider these approaches for organizing decentralized event handlers: 1. Group related event handlers in the same file 2. Place event handlers near the state classes they modify 3. For larger applications, create a dedicated `events` directory with files organized by feature ```python box # Example organization in a larger application # events/user_events.py @rx.event def update_user(state: UserState, name: str, age: int): state.name = name state.age = age @rx.event def delete_user(state: UserState): state.name = "" state.age = 0 ``` ### Combining with Other Event Features Decentralized event handlers work seamlessly with other Reflex event features: ```python box # Background event @rx.event(background=True) async def long_running_task(state: AppState): # Long-running task implementation pass # Event chaining @rx.event def process_form(state: FormState, data: dict): # Process form data return validate_data # Chain to another event ``` # Event Actions Source: http://localhost:3000/docs/events/event-actions.md ```python exec import reflex as rx import datetime ``` In Reflex, an event action is a special behavior that occurs during or after processing an event on the frontend. Event actions can modify how the browser handles DOM events or throttle and debounce events before they are processed by the backend. An event action is specified by accessing attributes and methods present on all EventHandlers and EventSpecs. ## DOM Event Propagation _Added in v0.3.2_ ### prevent_default The `.prevent_default` action prevents the default behavior of the browser for the action. This action can be added to any existing event, or it can be used on its own by specifying `rx.prevent_default` as an event handler. A common use case for this is to prevent navigation when clicking a link. ```python demo rx.link( "This Link Does Nothing", href="https://reflex.dev/", on_click=rx.prevent_default ) ``` ```python demo exec class LinkPreventDefaultState(rx.State): status: bool = False @rx.event def toggle_status(self): self.status = not self.status def prevent_default_example(): return rx.vstack( rx.heading(f"The value is {LinkPreventDefaultState.status}"), rx.link( "Toggle Value", href="https://reflex.dev/", on_click=LinkPreventDefaultState.toggle_status.prevent_default, ), ) ``` ### stop_propagation The `.stop_propagation` action stops the event from propagating to parent elements. This action is often used when a clickable element contains nested buttons that should not trigger the parent element's click event. In the following example, the first button uses `.stop_propagation` to prevent the click event from propagating to the outer vstack. The second button does not use `.stop_propagation`, so the click event will also be handled by the on_click attached to the outer vstack. ```python demo exec class StopPropagationState(rx.State): where_clicked: list[str] = [] @rx.event def handle_click(self, where: str): self.where_clicked.append(where) @rx.event def handle_reset(self): self.where_clicked = [] def stop_propagation_example(): return rx.vstack( rx.button( "btn1 - Stop Propagation", on_click=StopPropagationState.handle_click("btn1").stop_propagation, ), rx.button( "btn2 - Normal Propagation", on_click=StopPropagationState.handle_click("btn2"), ), rx.foreach(StopPropagationState.where_clicked, rx.text), rx.button( "Reset", on_click=StopPropagationState.handle_reset.stop_propagation, ), padding="2em", border=f"1px dashed {rx.color('accent', 5)}", on_click=StopPropagationState.handle_click("outer"), ) ``` ## Throttling and Debounce _Added in v0.5.0_ For events that are fired frequently, it can be useful to throttle or debounce them to avoid network latency and improve performance. These actions both take a single argument which specifies the delay time in milliseconds. ### throttle The `.throttle` action limits the number of times an event is processed within a a given time period. It is useful for `on_scroll` and `on_mouse_move` events which are fired very frequently, causing lag when handling them in the backend. ```md alert warning # Throttled events are discarded. There is no eventual delivery of any event that is triggered while the throttle period is active. Throttle is not appropriate for events when the final payload contains data that must be processed, like `on_change`. ``` In the following example, the `on_scroll` event is throttled to only fire every half second. ```python demo exec class ThrottleState(rx.State): last_scroll: datetime.datetime | None @rx.event def handle_scroll(self): self.last_scroll = datetime.datetime.now(datetime.timezone.utc) def scroll_box(): return rx.scroll_area( rx.heading("Scroll Me"), *[rx.text(f"Item {i}") for i in range(100)], height="75px", width="50%", border=f"1px solid {rx.color('accent', 5)}", on_scroll=ThrottleState.handle_scroll.throttle(500), ) def throttle_example(): return ( scroll_box(), rx.text( "Last Scroll Event: ", rx.moment(ThrottleState.last_scroll, format="HH:mm:ss.SSS"), ), ) ``` ```md alert info # Event Actions are Chainable Event actions can be chained together to create more complex event handling behavior. For example, you can throttle an event and prevent its default behavior in the same event handler: `on_click=MyState.handle_click.throttle(500).prevent_default`. ``` ### debounce The `.debounce` action delays the processing of an event until the specified timeout occurs. If another event is triggered during the timeout, the timer is reset and the original event is discarded. Debounce is useful for handling the final result of a series of events, such as moving a slider. ```md alert warning # Debounced events are discarded. When a new event is triggered during the debounce period, the original event is discarded. Debounce is not appropriate for events where each payload contains unique data that must be processed, like `on_key_down`. ``` In the following example, the slider's `on_change` handler, `update_value`, is only triggered on the backend when the slider value has not changed for half a second. ```python demo exec class DebounceState(rx.State): settled_value: int = 50 @rx.event def update_value(self, value: list[int | float]): self.settled_value = value[0] def debounced_slider(): return rx.slider( key=rx.State.router.session.session_id, default_value=[DebounceState.settled_value], on_change=DebounceState.update_value.debounce(500), width="100%", ) def debounce_example(): return rx.vstack( debounced_slider(), rx.text(f"Settled Value: {DebounceState.settled_value}"), ) ``` ```md alert info # Why set key on the slider? Setting `key` to the `session_id` with a dynamic `default_value` ensures that when the page is refreshed, the component will be re-rendered to reflect the updated default_value from the state. Without the `key` set, the slider would always display the original `settled_value` after a page reload, instead of its current value. ``` ## Temporal Events _Added in [v0.6.6](https://github.com/reflex-dev/reflex/releases/tag/v0.6.6)_ ### temporal The `.temporal` action prevents events from being queued when the backend is down. This is useful for non-critical events where you do not want them to pile up if there is a temporary connection issue. ```md alert warning # Temporal events are discarded when the backend is down. When the backend is unavailable, events with the `.temporal` action will be discarded rather than queued for later processing. Only use this for events where it is acceptable to lose some interactions during connection issues. ``` In the following example, the `rx.moment` component with `interval` and `on_change` uses `.temporal` to prevent periodic updates from being queued when the backend is down: ```python demo exec class TemporalState(rx.State): current_time: str = "" @rx.event def update_time(self): self.current_time = datetime.datetime.now().strftime("%H:%M:%S") def temporal_example(): return rx.vstack( rx.heading("Current Time:"), rx.heading(TemporalState.current_time), rx.moment( interval=1000, on_change=TemporalState.update_time.temporal, ), rx.text("Time updates will not be queued if the backend is down."), ) ``` # Event Arguments Source: http://localhost:3000/docs/events/event-arguments.md ```python exec import reflex as rx ``` The event handler signature needs to match the event trigger definition argument count. If the event handler takes two arguments, the event trigger must be able to provide two arguments. Here is a simple example: ```python demo exec class EventArgStateSlider(rx.State): value: int = 50 @rx.event def set_end(self, value: list[int | float]): self.value = value[0] def slider_max_min_step(): return rx.vstack( rx.heading(EventArgStateSlider.value), rx.slider( default_value=40, on_value_commit=EventArgStateSlider.set_end, ), width="100%", ) ``` The event trigger here is `on_value_commit` and it is called when the value changes at the end of an interaction. This event trigger passes one argument, which is the value of the slider. The event handler which is triggered by the event trigger must therefore take one argument, which is `value` here. Here is a form example: ```python demo exec class EventArgState(rx.State): form_data: dict = {} @rx.event def handle_submit(self, form_data: dict): """Handle the form submit.""" self.form_data = form_data def event_arg_example(): return rx.vstack( rx.form( rx.vstack( rx.input( placeholder="Name", name="name", ), rx.checkbox("Checked", name="check"), rx.button("Submit", type="submit"), ), on_submit=EventArgState.handle_submit, reset_on_submit=True, ), rx.divider(), rx.heading("Results"), rx.text(EventArgState.form_data.to_string()), ) ``` In this example the event trigger is the `on_submit` event of the form. The event handler is `handle_submit`. The `on_submit` event trigger passes one argument, the form data as a dictionary, to the `handle_submit` event handler. The `handle_submit` event handler must take one argument because the `on_submit` event trigger passes one argument. When the number of args accepted by an EventHandler differs from that provided by the event trigger, an `EventHandlerArgMismatch` error will be raised. ## Pass Additional Arguments to Event Handlers In some use cases, you want to pass additional arguments to your event handlers. To do this you can bind an event trigger to a lambda, which can call your event handler with the arguments you want. Try typing a color in an input below and clicking away from it to change the color of the input. ```python demo exec class ArgState(rx.State): colors: list[str] = ["rgba(245,168,152)", "MediumSeaGreen", "#DEADE3"] @rx.event def change_color(self, color: str, index: int): self.colors[index] = color def event_arguments_example(): return rx.hstack( rx.input( default_value=ArgState.colors[0], on_blur=lambda c: ArgState.change_color(c, 0), bg=ArgState.colors[0], ), rx.input( default_value=ArgState.colors[1], on_blur=lambda c: ArgState.change_color(c, 1), bg=ArgState.colors[1], ), rx.input( default_value=ArgState.colors[2], on_blur=lambda c: ArgState.change_color(c, 2), bg=ArgState.colors[2], ), ) ``` In this case, in we want to pass two arguments to the event handler `change_color`, the color and the index of the color to change. The `on_blur` event trigger passes the text of the input as an argument to the lambda, and the lambda calls the `change_color` event handler with the text and the index of the input. When the number of args accepted by a lambda differs from that provided by the event trigger, an `EventFnArgMismatch` error will be raised. ```md alert warning # Event Handler Parameters should provide type annotations. Like state vars, be sure to provide the right type annotations for the parameters in an event handler. ``` ## Events with Partial Arguments (Advanced) _Added in v0.5.0_ Event arguments in Reflex are passed positionally. Any additional arguments not passed to an EventHandler will be filled in by the event trigger when it is fired. The following two code samples are equivalent: ```python # Use a lambda to pass event trigger args to the EventHandler. rx.text(on_blur=lambda v: MyState.handle_update("field1", v)) # Create a partial that passes event trigger args for any args not provided to the EventHandler. rx.text(on_blur=MyState.handle_update("field1")) ``` # Events Overview Source: http://localhost:3000/docs/events/events-overview.md ```python exec import reflex as rx ``` Events are composed of two parts: Event Triggers and Event Handlers. - **Events Handlers** are how the State of a Reflex application is updated. They are triggered by user interactions with the UI, such as clicking a button or hovering over an element. Events can also be triggered by the page loading or by other events. - **Event triggers** are component props that create an event to be sent to an event handler. Each component supports a set of events triggers. They are described in each [component's documentation](/docs/library) in the event trigger section. ## Example Lets take a look at an example below. Try mousing over the heading to change the word. ```python demo exec class WordCycleState(rx.State): # The words to cycle through. text: list[str] = ["Welcome", "to", "Reflex", "!"] # The index of the current word. index: int = 0 @rx.event def next_word(self): self.index = (self.index + 1) % len(self.text) @rx.var def get_text(self) -> str: return self.text[self.index] def event_triggers_example(): return rx.heading( WordCycleState.get_text, on_mouse_over=WordCycleState.next_word, color="green", ) ``` In this example, the heading component has the **event trigger**, `on_mouse_over`. Whenever the user hovers over the heading, the `next_word` **event handler** will be called to cycle the word. Once the handler returns, the UI will be updated to reflect the new state. Adding the `@rx.event` decorator above the event handler is strongly recommended. This decorator enables proper static type checking, which ensures event handlers receive the correct number and types of arguments. # What's in this section? In the event section of the documentation, you will explore the different types of events supported by Reflex, along with the different ways to call them. # Page Load Events Source: http://localhost:3000/docs/events/page-load-events.md ```python exec import reflex as rx ``` You can also specify a function to run when the page loads. This can be useful for fetching data once vs on every render or state change. In this example, we fetch data when the page loads: ```python class State(rx.State): data: Dict[str, Any] @rx.event def get_data(self): # Fetch data self.data = fetch_data() @rx.page(on_load=State.get_data) def index(): return rx.text("A Beautiful App") ``` Another example would be checking if the user is authenticated when the page loads. If the user is not authenticated, we redirect them to the login page. If they are authenticated, we don't do anything, letting them access the page. This `on_load` event would be placed on every page that requires authentication to access. ```python class State(rx.State): authenticated: bool @rx.event def check_auth(self): # Check if user is authenticated self.authenticated = check_auth() if not self.authenticated: return rx.redirect("/login") @rx.page(on_load=State.check_auth) def index(): return rx.text("A Beautiful App") ``` # Setters Source: http://localhost:3000/docs/events/setters.md ```python exec import reflex as rx ``` Every base var has a built-in event handler to set it's value for convenience, called `set_VARNAME`. Say you wanted to change the value of the select component. You could write your own event handler to do this: ```python demo exec options: list[str] = ["1", "2", "3", "4"] class SetterState1(rx.State): selected: str = "1" @rx.event def change(self, value): self.selected = value def code_setter(): return rx.vstack( rx.badge(SetterState1.selected, color_scheme="green"), rx.select( options, on_change=lambda value: SetterState1.change(value), ), ) ``` Or you could could use a built-in setter for conciseness. ```python demo exec options: list[str] = ["1", "2", "3", "4"] class SetterState2(rx.State): selected: str = "1" @rx.event def set_selected(self, selected: str): self.selected = selected def code_setter_2(): return rx.vstack( rx.badge(SetterState2.selected, color_scheme="green"), rx.select( options, on_change=SetterState2.set_selected, ), ) ``` In this example, the setter for `selected` is `set_selected`. Both of these examples are equivalent. Setters are a great way to make your code more concise. But if you want to do something more complicated, you can always write your own function in the state. # Special Events Docs Source: http://localhost:3000/docs/events/special-events.md ```python exec import reflex as rx ``` Reflex also has built-in special events can be found in the [reference](/docs/api-reference/special-events). For example, an event handler can trigger an alert on the browser. ```python demo exec class SpecialEventsState(rx.State): @rx.event def alert(self): return rx.window_alert("Hello World!") def special_events_example(): return rx.button("Alert", on_click=SpecialEventsState.alert) ``` Special events can also be triggered directly in the UI by attaching them to an event trigger. ```python def special_events_example(): return rx.button("Alert", on_click=rx.window_alert("Hello World!")) ``` # Yielding Updates Source: http://localhost:3000/docs/events/yield-events.md ```python exec import reflex as rx ``` A regular event handler will send a `StateUpdate` when it has finished running. This works fine for basic event, but sometimes we need more complex logic. To update the UI multiple times in an event handler, we can `yield` when we want to send an update. To do so, we can use the Python keyword `yield`. For every yield inside the function, a `StateUpdate` will be sent to the frontend with the changes up to this point in the execution of the event handler. This example below shows how to yield 100 updates to the UI. ```python demo exec class MultiUpdateState(rx.State): count: int = 0 @rx.event def timed_update(self): for i in range(100): self.count += 1 yield def multi_update(): return rx.vstack( rx.text(MultiUpdateState.count), rx.button("Start", on_click=MultiUpdateState.timed_update), ) ``` Here is another example of yielding multiple updates with a loading icon. ```python demo exec import asyncio class ProgressExampleState(rx.State): count: int = 0 show_progress: bool = False @rx.event async def increment(self): self.show_progress = True yield # Think really hard. await asyncio.sleep(0.5) self.count += 1 self.show_progress = False def progress_example(): return rx.button( ProgressExampleState.count, on_click=ProgressExampleState.increment, loading=ProgressExampleState.show_progress, ) ``` ```md video https://youtube.com/embed/ITOZkzjtjUA?start=6463&end=6835 # Video: Asyncio with Yield ``` ## Yielding Other Events Events can also yield other events. This is useful when you want to chain events together. To do this, you can yield the event handler function itself. ```md alert # Reference other Event Handler via class When chaining another event handler with `yield`, access it via the state class, not `self`. ``` ```python demo exec import asyncio class YieldEventsState(rx.State): count: int = 0 show_progress: bool = False @rx.event async def add_five(self): self.show_progress = True yield # Think really hard. await asyncio.sleep(1) self.count += 5 self.show_progress = False @rx.event async def increment(self): yield YieldEventsState.add_five yield YieldEventsState.add_five yield YieldEventsState.add_five def multiple_yield_example(): return rx.button( YieldEventsState.count, on_click=YieldEventsState.increment, loading=YieldEventsState.show_progress, ) ``` # Basics Source: http://localhost:3000/docs/getting-started/basics.md ```python exec import reflex as rx ``` **~10 min** · An introduction to the most common concepts you'll use to build Reflex apps. ```md section # You will learn how to: - Create and nest components - Customize and style components - Distinguish between compile-time and runtime - Display data that changes over time - Respond to events and update the screen - Render conditions and lists - Create pages and navigate between them ``` If you haven't yet, [install Reflex](/docs/getting-started/installation) before continuing. Every example below imports the library as `rx`: ```python import reflex as rx ``` ## Creating and nesting components [Components](/docs/ui/overview) are the building blocks for your app's user interface (UI). They are the visual elements that make up your app, like buttons, text, and images. Reflex has a wide selection of [built-in components](/docs/library) to get you started quickly. Components are created using functions that return a component object. ```python demo exec def my_button(): return rx.button("Click Me") ``` Components can be nested inside each other to create complex UIs. To nest components as children, pass them as positional arguments to the parent component. In the example below, the `rx.text` and `my_button` components are children of the `rx.box` component. ```python demo exec def my_container(): return rx.box( rx.text("This is a page"), # Reference components defined in other functions. my_button(), ) ``` You can also use any base HTML element through the [rx.el](/docs/library/html/) namespace. This allows you to use standard HTML elements directly in your Reflex app when you need more control or when a specific component isn't available in the Reflex component library. ```python demo exec def my_div(): return rx.el.div( rx.el.p("Use base html!"), ) ``` If you need a component not provided by Reflex, you can check the [3rd party ecosystem](/docs/custom-components) or [wrap your own React component](/docs/wrapping-react/library-and-tags). ## Customizing and styling components Components can be customized using [props](/docs/components/props), which are passed in as keyword arguments to the component function. Each component has props that are specific to that component. Check the docs for the component you are using to see what props are available. ```python demo exec def half_filled_progress(): return rx.progress(value=50) ``` In addition to component-specific props, components can also be styled using CSS properties passed as props. ```python demo exec def round_button(): return rx.button("Click Me", border_radius="15px", font_size="18px") ``` ```md alert Use the `snake_case` version of the CSS property name as the prop name. ``` See the [styling guide](/docs/styling/overview) for more information on how to style components In summary, components are made up of children and props. ```md definition # Children - Text or other Reflex components nested inside a component. - Passed as **positional arguments**. # Props - Attributes that affect the behavior and appearance of a component. - Passed as **keyword arguments**. ``` ## Displaying data that changes over time Apps need to store and display data that changes over time. Reflex handles this through [State](/docs/state/overview), which is a Python class that stores variables that can change when the app is running, as well as the functions that can change those variables. To define a state class, subclass `rx.State` and define fields that store the state of your app. The state variables ([vars](/docs/vars/base-vars)) should have a type annotation, and can be initialized with a default value. ```python class MyState(rx.State): count: int = 0 ``` ### Referencing state vars in components To reference a state var in a component, you can pass it as a child or prop. The component will automatically update when the state changes. Vars are referenced through class attributes on your state class. For example, to reference the `count` var in a component, use `MyState.count`. ```python demo exec class MyState(rx.State): count: int = 0 color: str = "red" def counter(): return rx.hstack( # The heading `color` prop is set to the `color` var in MyState. rx.heading("Count: ", color=MyState.color), # The `count` var in `MyState` is passed as a child to the heading component. rx.heading(MyState.count), ) ``` Vars can be referenced in multiple components, and will automatically update when the state changes. ## Responding to events and updating the screen So far, we've defined state vars but we haven't shown how to change them. All state changes are handled through functions in the state class, called [event handlers](/docs/events/events-overview). ```md alert Event handlers are the **only** way to change state in Reflex. ``` Components have special props, such as `on_click`, called event triggers that can be used to make components interactive. Event triggers connect components to event handlers, which update the state. ```python demo exec class CounterState(rx.State): count: int = 0 @rx.event def increment(self): self.count += 1 def counter_increment(): return rx.hstack( rx.heading(CounterState.count), rx.button("Increment", on_click=CounterState.increment), ) ``` When an event trigger is activated, the event handler is called, which updates the state. The UI is automatically re-rendered to reflect the new state. ```md alert info # What is the `@rx.event` decorator? Adding the `@rx.event` decorator above the event handler is strongly recommended. This decorator enables proper static type checking, which ensures event handlers receive the correct number and types of arguments. This was introduced in Reflex version 0.6.5. ``` ### Event handlers with arguments Event handlers can also take in arguments. For example, the `increment` event handler can take an argument to increment the count by a specific amount. ```python demo exec class CounterState2(rx.State): count: int = 0 @rx.event def increment(self, amount: int): self.count += amount def counter_variable(): return rx.hstack( rx.heading(CounterState2.count), rx.button("Increment by 1", on_click=lambda: CounterState2.increment(1)), rx.button("Increment by 5", on_click=lambda: CounterState2.increment(5)), ) ``` The `on_click` event trigger doesn't pass any arguments here, but some event triggers do. For example, the `on_blur` event trigger passes the text of an input as an argument to the event handler. ```python demo exec class TextState(rx.State): text: str = "" @rx.event def update_text(self, new_text: str): self.text = new_text def text_input(): return rx.vstack( rx.heading(TextState.text), rx.input(default_value=TextState.text, on_blur=TextState.update_text), ) ``` ```md alert Make sure that the event handler has the same number of arguments as the event trigger, or an error will be raised. ``` ## Compile-time vs. runtime Before we dive deeper into state, it's important to understand the difference between compile-time and runtime in Reflex. When you run your app, the frontend gets compiled to Javascript code that runs in the browser (compile-time). The backend stays in Python and runs on the server during the lifetime of the app (runtime). ### When can you not use pure Python? We cannot compile arbitrary Python code, only the components that you define. What this means importantly is that you cannot use arbitrary Python operations and functions on state vars in components. However, since any event handlers in your state are on the backend, you **can use any Python code or library** within your state. ### Examples that work Within an event handler, use any Python code or library. ```python demo exec def check_even(num: int): return num % 2 == 0 class MyState3(rx.State): count: int = 0 text: str = "even" @rx.event def increment(self): # Use any Python code within state. # Even reference functions defined outside the state. if check_even(self.count): self.text = "even" else: self.text = "odd" self.count += 1 def count_and_check(): return rx.box( rx.heading(MyState3.text), rx.button("Increment", on_click=MyState3.increment) ) ``` Use any Python function within components, as long as it is defined at compile time (i.e. does not reference any state var) ```python demo exec def show_numbers(): return rx.vstack(*[rx.hstack(i, check_even(i)) for i in range(10)]) ``` ### Examples that don't work You cannot do an `if` statement on vars in components, since the value is not known at compile time. ```python class BadState(rx.State): count: int = 0 def count_if_even(): return rx.box( rx.heading("Count: "), # This will raise a compile error, as BadState.count is a var and not known at compile time. rx.text(BadState.count if BadState.count % 2 == 0 else "Odd"), # Using an if statement with a var as a prop will NOT work either. rx.text("hello", color="red" if BadState.count % 2 == 0 else "blue"), ) ``` You cannot do a `for` loop over a list of vars. ```python class BadState(rx.State): items: list[str] = ["Apple", "Banana", "Cherry"] def loop_over_list(): return rx.box( # This will raise a compile error, as BadState.items is a list and not known at compile time. *[rx.text(item) for item in BadState.items] ) ``` You cannot do arbitrary Python operations on state vars in components. ```python class BadTextState(rx.State): text: str = "Hello world" def format_text(): return rx.box( # Python operations such as `len` will not work on state vars. rx.text(len(BadTextState.text)), ) ``` In the next sections, we will show how to handle these cases. ## Conditional rendering As mentioned above, you cannot use Python `if/else` statements with state vars in components. Instead, use the [rx.cond](/docs/components/conditional-rendering) function to conditionally render components. ```python demo exec class LoginState(rx.State): logged_in: bool = False @rx.event def toggle_login(self): self.logged_in = not self.logged_in def show_login(): return rx.box( rx.cond( LoginState.logged_in, rx.heading("Logged In"), rx.heading("Not Logged In"), ), rx.button("Toggle Login", on_click=LoginState.toggle_login), ) ``` ## Rendering lists To iterate over a var that is a list, use the [rx.foreach](/docs/components/rendering-iterables) function to render a list of components. Pass the list var and a function that returns a component as arguments to `rx.foreach`. ```python demo exec class ListState(rx.State): items: list[str] = ["Apple", "Banana", "Cherry"] def render_item(item: rx.Var[str]): """Render a single item.""" # Note that item here is a Var, not a str! return rx.list.item(item) def show_fruits(): return rx.box( rx.foreach(ListState.items, render_item), ) ``` The function that renders each item takes in a `Var`, since this will get compiled up front. ## Var Operations You can't use arbitrary Python operations on state vars in components, but Reflex has [var operations](/docs/vars/var-operations) that you can use to manipulate state vars. For example, to check if a var is even, you can use the `%` and `==` var operations. ```python demo exec class CountEvenState(rx.State): count: int = 0 @rx.event def increment(self): self.count += 1 def count_if_even(): return rx.box( rx.heading("Count: "), rx.cond( # Here we use the `%` and `==` var operations to check if the count is even. CountEvenState.count % 2 == 0, rx.text("Even"), rx.text("Odd"), ), rx.button("Increment", on_click=CountEvenState.increment), ) ``` ## App and Pages Reflex apps are created by instantiating the `rx.App` class. Pages are linked to specific URL routes, and are created by defining a function that returns a component. ```python def index(): return rx.text("Root Page") app = rx.App() app.add_page(index, route="/") ``` ## Next Steps You've got the core pieces — components, state, events, compile-time vs. runtime. Time to build. ```md alert info # Build something real - [Dashboard tutorial](/docs/getting-started/dashboard-tutorial) — a data app with tables, forms, and state. - [Chatapp tutorial](/docs/getting-started/chatapp-tutorial) — streaming AI responses end-to-end. - [Open-source templates](/docs/getting-started/open-source-templates) — full apps to fork. ``` ```md alert info # Go deeper - [Vars](/docs/vars/base-vars) and [var operations](/docs/vars/var-operations) — the full API. - [Events](/docs/events/events-overview) and [pages](/docs/pages/overview) — routing, triggers, handlers. - [How Reflex works](/docs/advanced-onboarding/how-reflex-works) — what runs where, and why. ``` # AI Chat App Source: http://localhost:3000/docs/getting-started/chatapp-tutorial.md ```python exec import os import reflex as rx import openai from docs.getting_started import chat_tutorial_style as style from docs.getting_started.chat_tutorial_utils import ChatappState # If it's in environment, no need to hardcode (openai SDK will pick it up) if "OPENAI_API_KEY" not in os.environ: openai.api_key = "YOUR_OPENAI_KEY" ``` **~30 min hands-on** · Build a streaming AI chatbot in pure Python — UI, state, and OpenAI integration in one Reflex app. You can find the full source code for this app on [GitHub](https://github.com/reflex-dev/reflex-chat). ```python eval rx.box( rx.vstack( rx.vstack( rx.box( rx.text("What is Reflex?", style=style.question_style), text_align="right", width="100%", ), rx.box( rx.text( "Reflex is a way to build full-stack web apps in pure Python — " "frontend, backend, and state all in one place.", style=style.answer_style, ), text_align="left", width="100%", ), rx.box( rx.text("Can I deploy it?", style=style.question_style), text_align="right", width="100%", ), rx.box( rx.text( "Yes! A single `reflex deploy` ships it to production.", style=style.answer_style, ), text_align="left", width="100%", ), spacing="0", width="100%", ), rx.hstack( rx.input( placeholder="Ask a question", style=style.input_style, is_disabled=True, ), rx.button("Ask", style=style.button_style, is_disabled=True), spacing="3", padding_top="1.5em", justify="center", width="100%", ), align="stretch", spacing="0", width="100%", padding="2.5em 4em", ), border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", margin_y="1em", ) ``` ## What You'll Learn In this tutorial you'll learn how to: 1. Install `reflex` and set up your development environment. 2. Create components to define and style your UI. 3. Use state to add interactivity to your app. 4. Deploy your app to share with others. ## Setting up Your Project ```md video https://youtube.com/embed/ITOZkzjtjUA?start=175&end=445 # Video: Example of Setting up the Chat App ``` We will start by creating a new project and setting up our development environment. If you haven't installed [uv](https://docs.astral.sh/uv/) yet, see the [installation guide](/docs/getting-started/installation). Then create a new project directory and scaffold a Reflex app: ```bash mkdir chatapp cd chatapp uv init uv add reflex uv run reflex init ``` ```md alert info When prompted to select a template, choose option **0** for a blank project. ``` You can run the template app to make sure everything is working. ```bash uv run reflex run ``` You should see your app running at [http://localhost:3000](http://localhost:3000). Reflex also starts the backend server which handles all the state management and communication with the frontend. You can test the backend server is running by navigating to [http://localhost:8000/ping](http://localhost:8000/ping). Now that we have our project set up, in the next section we will start building our app! ## Basic Frontend Let's start with defining the frontend for our chat app. In Reflex, the frontend can be broken down into independent, reusable components. See the [components docs](/docs/components/props) for more information. ### Display Q&A We will modify the `index` function in `chatapp/chatapp.py` file to return a component that displays a single question and answer. ```python demo box rx.container( rx.box( "What is Reflex?", # The user's question is on the right. text_align="right", ), rx.box( "A way to build web apps in pure Python!", # The answer is on the left. text_align="left", ), ) ``` ```python # chatapp.py import reflex as rx def index() -> rx.Component: return rx.container( rx.box( "What is Reflex?", # The user's question is on the right. text_align="right", ), rx.box( "A way to build web apps in pure Python!", # The answer is on the left. text_align="left", ), ) # Add state and page to the app. app = rx.App() app.add_page(index) ``` Components can be nested inside each other to create complex layouts. Here we create a parent container that contains two boxes for the question and answer. We also add some basic styling to the components. Components take in keyword arguments, called [props](/docs/components/props), that modify the appearance and functionality of the component. We use the `text_align` prop to align the text to the left and right. ### Reusing Components Now that we have a component that displays a single question and answer, we can reuse it to display multiple questions and answers. We will move the component to a separate function `question_answer` and call it from the `index` function. ```python exec def qa(question: str, answer: str) -> rx.Component: return rx.box( rx.box(question, text_align="right"), rx.box(answer, text_align="left"), margin_y="1em", ) qa_pairs = [ ("What is Reflex?", "A way to build web apps in pure Python!"), ( "What can I make with it?", "Anything from a simple website to a complex web app!", ), ] def chat() -> rx.Component: qa_pairs = [ ("What is Reflex?", "A way to build web apps in pure Python!"), ( "What can I make with it?", "Anything from a simple website to a complex web app!", ), ] return rx.box(*[qa(question, answer) for question, answer in qa_pairs]) ``` ```python demo box rx.container(chat()) ``` ```python def qa(question: str, answer: str) -> rx.Component: return rx.box( rx.box(question, text_align="right"), rx.box(answer, text_align="left"), margin_y="1em", ) def chat() -> rx.Component: qa_pairs = [ ("What is Reflex?", "A way to build web apps in pure Python!"), ( "What can I make with it?", "Anything from a simple website to a complex web app!", ), ] return rx.box(*[qa(question, answer) for question, answer in qa_pairs]) def index() -> rx.Component: return rx.container(chat()) ``` ### Chat Input Now we want a way for the user to input a question. For this, we will use the [input](/docs/library/forms/input) component to have the user add text and a [button](/docs/library/forms/button) component to submit the question. ```python exec def action_bar() -> rx.Component: return rx.hstack( rx.input(placeholder="Ask a question"), rx.button("Ask"), ) ``` ```python demo box rx.container( chat(), action_bar(), ) ``` ```python def action_bar() -> rx.Component: return rx.hstack( rx.input(placeholder="Ask a question"), rx.button("Ask"), ) def index() -> rx.Component: return rx.container( chat(), action_bar(), ) ``` ### Styling Let's add some styling to the app. More information on styling can be found in the [styling docs](/docs/styling/overview). To keep our code clean, we will move the styling to a separate file `chatapp/style.py`. ```python # style.py import reflex as rx # Common styles for questions and answers. shadow = "rgba(0, 0, 0, 0.15) 0px 2px 8px" chat_margin = "20%" message_style = dict( padding="1em", border_radius="5px", margin_y="0.5em", box_shadow=shadow, max_width="30em", display="inline-block", ) # Set specific styles for questions and answers. question_style = message_style | dict( margin_left=chat_margin, background_color=rx.color("gray", 4) ) answer_style = message_style | dict( margin_right=chat_margin, background_color=rx.color("accent", 8) ) # Styles for the action bar. input_style = dict( border_width="1px", padding="0.5em", box_shadow=shadow, width="350px" ) button_style = dict(background_color=rx.color("accent", 10), box_shadow=shadow) ``` We will import the styles in `chatapp.py` and use them in the components. At this point, the app should look like this: ```python exec def qa4(question: str, answer: str) -> rx.Component: return rx.box( rx.box(rx.text(question, style=style.question_style), text_align="right"), rx.box(rx.text(answer, style=style.answer_style), text_align="left"), margin_y="1em", width="100%", ) def chat4() -> rx.Component: qa_pairs = [ ("What is Reflex?", "A way to build web apps in pure Python!"), ( "What can I make with it?", "Anything from a simple website to a complex web app!", ), ] return rx.box(*[qa4(question, answer) for question, answer in qa_pairs]) def action_bar4() -> rx.Component: return rx.hstack( rx.input(placeholder="Ask a question", style=style.input_style), rx.button("Ask", style=style.button_style), ) ``` ```python demo box rx.center( rx.vstack( chat4(), action_bar4(), align="center", ) ) ``` ```python # chatapp.py import reflex as rx from chatapp import style def qa(question: str, answer: str) -> rx.Component: return rx.box( rx.box(rx.text(question, style=style.question_style), text_align="right"), rx.box(rx.text(answer, style=style.answer_style), text_align="left"), margin_y="1em", width="100%", ) def chat() -> rx.Component: qa_pairs = [ ("What is Reflex?", "A way to build web apps in pure Python!"), ( "What can I make with it?", "Anything from a simple website to a complex web app!", ), ] return rx.box(*[qa(question, answer) for question, answer in qa_pairs]) def action_bar() -> rx.Component: return rx.hstack( rx.input(placeholder="Ask a question", style=style.input_style), rx.button("Ask", style=style.button_style), ) def index() -> rx.Component: return rx.center( rx.vstack( chat(), action_bar(), align="center", ) ) app = rx.App() app.add_page(index) ``` The app is looking good, but it's not very useful yet! In the next section, we will add some functionality to the app. ## State Now let’s make the chat app interactive by adding state. The state is where we define all the variables that can change in the app and all the functions that can modify them. You can learn more about state in the [state docs](/docs/state/overview). ### Defining State We will create a new file called `state.py` in the `chatapp` directory. Our state will keep track of the current question being asked and the chat history. We will also define an event handler `answer` which will process the current question and add the answer to the chat history. ```python # state.py import reflex as rx class State(rx.State): # The current question being asked. question: str # Keep track of the chat history as a list of (question, answer) tuples. chat_history: list[tuple[str, str]] @rx.event def answer(self): # Our chatbot is not very smart right now... answer = "I don't know!" self.chat_history.append((self.question, answer)) ``` ### Binding State to Components Now we can import the state in `chatapp.py` and reference it in our frontend components. We will modify the `chat` component to use the state instead of the current fixed questions and answers. ```python exec def qa(question: str, answer: str) -> rx.Component: return rx.box( rx.box(rx.text(question, style=style.question_style), text_align="right"), rx.box(rx.text(answer, style=style.answer_style), text_align="left"), margin_y="1em", width="100%", ) def chat1() -> rx.Component: return rx.box( rx.foreach( ChatappState.chat_history, lambda messages: qa(messages[0], messages[1]) ) ) def action_bar1() -> rx.Component: return rx.hstack( rx.input( placeholder="Ask a question", on_change=ChatappState.set_question, style=style.input_style, ), rx.button("Ask", on_click=ChatappState.answer, style=style.button_style), ) ``` ```python demo box rx.container( chat1(), action_bar1(), ) ``` ```python # chatapp.py from chatapp.state import State def chat() -> rx.Component: return rx.box( rx.foreach(State.chat_history, lambda messages: qa(messages[0], messages[1])) ) def action_bar() -> rx.Component: return rx.hstack( rx.input( placeholder="Ask a question", on_change=State.set_question1, style=style.input_style, ), rx.button("Ask", on_click=State.answer, style=style.button_style), ) ``` Normal Python `for` loops don't work for iterating over state vars because these values can change and aren't known at compile time. Instead, we use the [foreach](/docs/library/dynamic-rendering/foreach) component to iterate over the chat history. We also bind the input's `on_change` event to the `set_question` event handler, which will update the `question` state var while the user types in the input. We bind the button's `on_click` event to the `answer` event handler, which will process the question and add the answer to the chat history. The `set_question` event handler is a built-in implicitly defined event handler. Every base var has one. Learn more in the [events docs](/docs/events/setters) under the Setters section. ### Clearing the Input Currently the input doesn't clear after the user clicks the button. We can fix this by binding the value of the input to `question`, with `value=State.question`, and clear it when we run the event handler for `answer`, with `self.question = ''`. ```python exec def action_bar2() -> rx.Component: return rx.hstack( rx.input( value=ChatappState.question, placeholder="Ask a question", on_change=ChatappState.set_question, style=style.input_style, ), rx.button("Ask", on_click=ChatappState.answer2, style=style.button_style), ) ``` ```python demo box rx.container( chat1(), action_bar2(), ) ``` ```python # chatapp.py def action_bar() -> rx.Component: return rx.hstack( rx.input( value=State.question, placeholder="Ask a question", on_change=State.set_question2, style=style.input_style, ), rx.button("Ask", on_click=State.answer, style=style.button_style), ) ``` ```python # state.py @rx.event def answer(self): # Our chatbot is not very smart right now... answer = "I don't know!" self.chat_history.append((self.question, answer)) self.question = "" ``` ### Streaming Text Normally state updates are sent to the frontend when an event handler returns. However, we want to stream the text from the chatbot as it is generated. We can do this by yielding from the event handler. See the [yield events docs](/docs/events/yield-events) for more info. ```python exec def action_bar3() -> rx.Component: return rx.hstack( rx.input( value=ChatappState.question, placeholder="Ask a question", on_change=ChatappState.set_question, style=style.input_style, ), rx.button("Ask", on_click=ChatappState.answer3, style=style.button_style), ) ``` ```python demo box rx.container( chat1(), action_bar3(), ) ``` ```python # state.py import asyncio async def answer(self): # Our chatbot is not very smart right now... answer = "I don't know!" self.chat_history.append((self.question, "")) # Clear the question input. self.question = "" # Yield here to clear the frontend input before continuing. yield for i in range(len(answer)): # Pause to show the streaming effect. await asyncio.sleep(0.1) # Add one letter at a time to the output. self.chat_history[-1] = (self.chat_history[-1][0], answer[: i + 1]) yield ``` In the next section, we will finish our chatbot by adding AI! ## Final App We will use OpenAI's API to give our chatbot some intelligence. ### Configure OpenAI First, ensure you have an active OpenAI subscription and install the latest `openai` package: ```bash pip install --upgrade openai ``` Then export your API key so the app can read it at runtime: ```bash export OPENAI_API_KEY="sk-..." ``` ### Using the API Making your chatbot intelligent requires connecting to a language model API. This section explains how to integrate with OpenAI's API to power your chatbot's responses. 1. First, the user types a prompt that is updated via the `on_change` event handler. 2. Next, when a prompt is ready, the user can choose to submit it by clicking the `Ask` button which in turn triggers the `State.answer` method inside our `state.py` file. 3. Finally, if the method is triggered, the `prompt` is sent via a request to OpenAI client and returns an answer that we can trim and use to update the chat history! ```python # chatapp.py def action_bar() -> rx.Component: return rx.hstack( rx.input( value=State.question, placeholder="Ask a question", # on_change event updates the input as the user types a prompt. on_change=State.set_question3, style=style.input_style, ), # on_click event triggers the API to send the prompt to OpenAI. rx.button("Ask", on_click=State.answer, style=style.button_style), ) ``` ```python # state.py import os from openai import AsyncOpenAI @rx.event async def answer(self): # Our chatbot has some brains now! client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"]) session = await client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": self.question}], stop=None, temperature=0.7, stream=True, ) # Add to the answer as the chatbot responds. answer = "" self.chat_history.append((self.question, answer)) # Clear the question input. self.question = "" # Yield here to clear the frontend input before continuing. yield async for item in session: if hasattr(item.choices[0].delta, "content"): if item.choices[0].delta.content is None: # presence of 'None' indicates the end of the response break answer += item.choices[0].delta.content self.chat_history[-1] = (self.chat_history[-1][0], answer) yield ``` Finally, we have our chatbot! ### Final Code The finished project is split across three files — `chatapp.py` for UI and app setup, `state.py` for state and API integration, and `style.py` for styling: ```text chatapp/ ├── chatapp.py ├── state.py └── style.py ``` The `chatapp.py` file: ```python import reflex as rx from chatapp import style from chatapp.state import State def qa(question: str, answer: str) -> rx.Component: return rx.box( rx.box(rx.text(question, style=style.question_style), text_align="right"), rx.box(rx.text(answer, style=style.answer_style), text_align="left"), margin_y="1em", ) def chat() -> rx.Component: return rx.box( rx.foreach( State.chat_history, lambda messages: qa(messages[0], messages[1]), ) ) def action_bar() -> rx.Component: return rx.hstack( rx.input( value=State.question, placeholder="Ask a question", on_change=State.set_question, style=style.input_style, ), rx.button( "Ask", on_click=State.answer, style=style.button_style, ), ) def index() -> rx.Component: return rx.center( rx.vstack( chat(), action_bar(), align="center", ) ) app = rx.App() app.add_page(index) ``` The `state.py` file: ```python import os from openai import AsyncOpenAI import reflex as rx class State(rx.State): question: str chat_history: list[tuple[str, str]] = [] async def answer(self): client = AsyncOpenAI(api_key=os.environ["OPENAI_API_KEY"]) # Start streaming completion from OpenAI session = await client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": self.question}], temperature=0.7, stream=True, ) # Initialize response and update UI answer = "" self.chat_history.append((self.question, answer)) self.question = "" yield # Process streaming response async for item in session: if hasattr(item.choices[0].delta, "content"): if item.choices[0].delta.content is None: break answer += item.choices[0].delta.content self.chat_history[-1] = (self.chat_history[-1][0], answer) yield ``` The `style.py` file: ```python import reflex as rx # Common style base shadow = "rgba(0, 0, 0, 0.15) 0px 2px 8px" chat_margin = "20%" message_style = dict( padding="1em", border_radius="5px", margin_y="0.5em", box_shadow=shadow, max_width="30em", display="inline-block", ) # Styles for questions and answers question_style = message_style | dict( margin_left=chat_margin, background_color=rx.color("gray", 4), ) answer_style = message_style | dict( margin_right=chat_margin, background_color=rx.color("accent", 8), ) # Styles for input elements input_style = dict( border_width="1px", padding="0.5em", box_shadow=shadow, width="350px" ) button_style = dict(background_color=rx.color("accent", 10), box_shadow=shadow) ``` ### Next Steps Congratulations! You have built your first chatbot. From here, you can read through the rest of the documentations to learn about Reflex in more detail. The best way to learn is to build something, so try to build your own app using this as a starting point! ### One More Thing With our hosting service, you can deploy this app with a single command within minutes. Check out our [Hosting Quick Start](https://reflex.dev/docs/hosting/deploy-quick-start/). # Data Dashboard Source: http://localhost:3000/docs/getting-started/dashboard-tutorial.md ```python exec import reflex as rx ``` **~20 min hands-on** · Build a small data dashboard where users can input data that renders in a table and a graph. This tutorial does not assume any existing Reflex knowledge, but we do recommend checking out the quick [Basics Guide](/docs/getting-started/basics) first. The techniques you'll learn are fundamental to any Reflex app. This tutorial is divided into several sections: - **Setup**: Get your machine ready. - **Overview**: Components and props. - **Dynamic data with State**: Render data that changes. - **Add data with a form**: Forms + event handlers. - **Plot a graph**: Reflex's graphing components. - **Customize** + **[Full app](#full-app-styled)**: Customize and see the finished code. ## What are you building? An interactive data dashboard: a table of users, a form to add more, and a bar chart that updates as data changes. Want to skip ahead? Jump to the [Full app](#full-app-styled) at the bottom. ```python exec import dataclasses from collections import Counter @dataclasses.dataclass class User: """The user model.""" name: str email: str gender: str class State5(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] users_for_graph: list[dict] = [] def add_user(self, form_data: dict): self.users.append(User(**form_data)) self.transform_data() return rx.toast.info( f"User {form_data['name']} has been added.", position="bottom-right", ) def transform_data(self): """Transform user gender group data into a format suitable for visualization in graphs.""" # Count users of each gender group gender_counts = Counter(user.gender for user in self.users) # Transform into list of dict so it can be used in the graph self.users_for_graph = [ {"name": gender_group, "value": count} for gender_group, count in gender_counts.items() ] def show_user5(user: User): """Show a user in a table row.""" return rx.table.row( rx.table.cell(user.name), rx.table.cell(user.email), rx.table.cell(user.gender), style={"_hover": {"bg": rx.color("gray", 3)}}, align="center", ) def add_customer_button5() -> rx.Component: return rx.dialog.root( rx.dialog.trigger( rx.button( rx.icon("plus", size=26), rx.text("Add User", size="4"), ), ), rx.dialog.content( rx.dialog.title( "Add New User", ), rx.dialog.description( "Fill the form with the user's info", ), rx.form( rx.flex( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="male", name="gender", ), rx.flex( rx.dialog.close( rx.button( "Cancel", variant="soft", color_scheme="gray", ), ), rx.dialog.close( rx.button("Submit", type="submit"), ), spacing="3", justify="end", ), direction="column", spacing="4", ), on_submit=State5.add_user, reset_on_submit=False, ), max_width="450px", ), ) def graph5(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="value", fill=rx.color("accent", 9), radius=6, bar_size=48, ), rx.recharts.x_axis( data_key="name", tick_line=False, axis_line=False, padding={"left": 24, "right": 24}, ), rx.recharts.y_axis( tick_line=False, axis_line=False, allow_decimals=False, ), rx.recharts.cartesian_grid( stroke_dasharray="3 3", vertical=False, stroke=rx.color("slate", 4), ), data=State5.users_for_graph, width="100%", height=200, margin={"top": 8, "right": 8, "bottom": 0, "left": 0}, ) ``` ```python eval rx.box( rx.vstack( rx.hstack( rx.vstack( rx.text( "Users", size="4", weight="bold", color=rx.color("slate", 12), text_align="left", width="100%", ), rx.text( "Add customers and watch the chart update.", size="2", color=rx.color("slate", 10), text_align="left", width="100%", ), spacing="1", align="start", ), rx.spacer(), add_customer_button5(), align="center", width="100%", ), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State5.users, show_user5), ), variant="surface", size="2", width="100%", ), graph5(), align="stretch", width="100%", on_mouse_enter=State5.transform_data, spacing="4", padding="1.75em 2em", ), border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", margin_y="1em", background=rx.color("slate", 1), ) ``` ## Setup 1. [Install Reflex](/docs/getting-started/installation) if you haven't already. 2. Create a folder called `dashboard_tutorial` and `cd` into it. 3. Run `uv init` and `uv add reflex`. 4. Run `uv run reflex init` and choose template `0` (the blank template). 5. Run `uv run reflex run` to start the app and confirm everything works. ## Overview ### Starter code The `reflex init` command scaffolds an `rxconfig.py` (app [config](/docs/advanced-onboarding/configuration)), an `assets/` folder for static files, and a `dashboard_tutorial/dashboard_tutorial.py` module containing your app. Open that module and replace its contents — we'll build the app up from scratch. A minimal Reflex page is just a component function plus an app that registers it: ```python import reflex as rx def index() -> rx.Component: return rx.text("Hello World!") app = rx.App() app.add_page(index) ``` ```md alert info For the rest of the tutorial the `app = rx.App()` and `app.add_page` lines are implied and not shown — we'll come back to them in [Customize](#customize). ``` ### Create a table The `rx.table` component has a `root` that wraps a `header` and a `body`. The header takes `row` → `column_header_cell` components; the body takes `row` → `cell` components holding the actual data. Props like `variant` and `size` customize the look: ```python eval rx.box( rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.table.row( rx.table.cell("Danilo Sousa"), rx.table.cell("danilo@example.com"), rx.table.cell("Male"), ), rx.table.row( rx.table.cell("Zahra Ambessa"), rx.table.cell("zahra@example.com"), rx.table.cell("Female"), ), ), variant="surface", size="3", ), border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", padding="2em", ) ``` ```python def index() -> rx.Component: return rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.table.row( rx.table.cell("Danilo Sousa"), rx.table.cell("danilo@example.com"), rx.table.cell("Male"), ), rx.table.row( rx.table.cell("Zahra Ambessa"), rx.table.cell("zahra@example.com"), rx.table.cell("Female"), ), ), variant="surface", size="3", ) ``` ## Dynamic data with State The table above is static — the rows are hardcoded. To make it dynamic, we move the data onto **state**: a Python class whose fields ([state vars](/docs/state/overview)) hold the app's data and whose methods ([event handlers](/docs/events/events-overview)) mutate them. We'll model each row as a `User` dataclass so we can access fields by name (`user.name`) instead of by index: ```python import dataclasses @dataclasses.dataclass class User: name: str email: str gender: str class State(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] ``` To iterate a list state var, use [`rx.foreach`](/docs/components/rendering-iterables) — it takes an iterable and a function that renders each item. Here `show_user` receives a `User` and returns a `table.row`: ```python def show_user(user: User) -> rx.Component: return rx.table.row( rx.table.cell(user.name), rx.table.cell(user.email), rx.table.cell(user.gender), ) def index() -> rx.Component: return rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State.users, show_user), ), variant="surface", size="3", ) ``` ```md alert info # Why not a `for` loop? A regular `for` loop runs at compile time, but state vars change at runtime — so the rendered rows wouldn't update. `rx.foreach` tells the compiler to re-render when the state var changes. See [compile-time vs runtime](/docs/getting-started/basics#compile-time-vs.-runtime). ``` ```python exec import dataclasses @dataclasses.dataclass class User: """The user model.""" name: str email: str gender: str class State2(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] def show_user2(user: User): """Show a person in a table row.""" return rx.table.row( rx.table.cell(user.name), rx.table.cell(user.email), rx.table.cell(user.gender), ) ``` ```python eval rx.box( rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State2.users, show_user2), ), variant="surface", size="3", ), border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", padding="2em", ) ``` The table looks the same, but the rows now come from state — next we'll add a form that appends to `State.users` so new rows appear automatically. ## Add data with a form We build a form using `rx.form`, which takes several components such as `rx.input` and `rx.select`, which represent the form fields that allow you to add information to submit with the form. Check out the [form](/docs/library/forms/form) docs for more information on form components. The `rx.input` component takes in several props. The `placeholder` prop is the text that is displayed in the input field when it is empty. The `name` prop is the name of the input field, which gets passed through in the dictionary when the form is submitted. The `required` prop is a boolean that determines if the input field is required. The `rx.select` component takes in a list of options that are displayed in the dropdown. The other props used here are identical to the `rx.input` component. ```python demo rx.form( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), ) ``` This form is all very compact as you can see from the example, so we need to add some styling to make it look better. We can do this by adding a `vstack` component around the form fields. The `vstack` component stacks the form fields vertically. Check out the [layout](/docs/styling/layout) docs for more information on how to layout your app. ```python demo rx.form( rx.vstack( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), ), ) ``` Now you have probably realised that we have all the form fields, but we have no way to submit the form. We can add a submit button to the form by adding a `rx.button` component to the `vstack` component. The `rx.button` component takes in the text that is displayed on the button and the `type` prop which is the type of button. The `type` prop is set to `submit` so that the form is submitted when the button is clicked. In addition to this we need a way to update the `users` state variable when the form is submitted. All state changes are handled through functions in the state class, called [event handlers](/docs/events/events-overview). Components have special props called event triggers, such as `on_submit`, that can be used to make components interactive. Event triggers connect components to event handlers, which update the state. Different event triggers expect the event handler that you hook them up to, to take in different arguments (and some do not take in any arguments). The `on_submit` event trigger of `rx.form` is hooked up to the `add_user` event handler that is defined in the `State` class. This event trigger expects to pass a `dict`, containing the form data, to the event handler that it is hooked up to. The `add_user` event handler takes in the form data as a dictionary and appends it to the `users` state variable. ```python class State(rx.State): ... def add_user(self, form_data: dict): self.users.append(User(**form_data)) def form(): return rx.form( rx.vstack( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), rx.button("Submit", type="submit"), ), on_submit=State.add_user, reset_on_submit=True, ) ``` Finally we must add the new `form()` component we have defined to the `index()` function so that the form is rendered on the page. Below is the full code for the app so far. If you try this form out you will see that you can add new users to the table by filling out the form and clicking the submit button. The form data will also appear as a toast (a small window in the corner of the page) on the screen when submitted. ```python exec class State3(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] def add_user(self, form_data: dict): self.users.append(User(**form_data)) return rx.toast.info( f"User has been added: {form_data}.", position="bottom-right", ) def show_user(user: User): """Show a person in a table row.""" return rx.table.row( rx.table.cell(user.name), rx.table.cell(user.email), rx.table.cell(user.gender), ) def form(): return rx.form( rx.vstack( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), rx.button("Submit", type="submit"), ), on_submit=State3.add_user, reset_on_submit=True, ) ``` ```python eval rx.vstack( form(), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State3.users, show_user), ), variant="surface", size="3", ), spacing="4", border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", padding="2em", ) ``` ```python class State(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] def add_user(self, form_data: dict): self.users.append(User(**form_data)) def show_user(user: User): """Show a person in a table row.""" return rx.table.row( rx.table.cell(user.name), rx.table.cell(user.email), rx.table.cell(user.gender), ) def form(): return rx.form( rx.vstack( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), rx.button("Submit", type="submit"), ), on_submit=State.add_user, reset_on_submit=True, ) def index() -> rx.Component: return rx.vstack( form(), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State.users, show_user), ), variant="surface", size="3", ), ) ``` ### Put the form in a dialog In Reflex, we like to make the user interaction as intuitive as possible. Placing the form we just constructed in an overlay creates a focused interaction by dimming the background, and ensures a cleaner layout when you have multiple action points such as editing and deleting as well. We will place the form inside of a `rx.dialog` component (also called a modal). The `rx.dialog.root` contains all the parts of a dialog, and the `rx.dialog.trigger` wraps the control that will open the dialog. In our case the trigger will be an `rx.button` that says "Add User" as shown below. ```python rx.dialog.trigger( rx.button( rx.icon("plus", size=26), rx.text("Add User", size="4"), ), ) ``` After the trigger we have the `rx.dialog.content` which contains everything within our dialog, including a title, a description and our form. The first way to close the dialog is without submitting the form and the second way is to close the dialog by submitting the form as shown below. This requires two `rx.dialog.close` components within the dialog. ```python ( rx.dialog.close( rx.button( "Cancel", variant="soft", color_scheme="gray", ), ), ) rx.dialog.close( rx.button("Submit", type="submit"), ) ``` The total code for the dialog with the form in it is below. ```python demo rx.dialog.root( rx.dialog.trigger( rx.button( rx.icon("plus", size=26), rx.text("Add User", size="4"), ), ), rx.dialog.content( rx.dialog.title( "Add New User", ), rx.dialog.description( "Fill the form with the user's info", ), rx.form( # flex is similar to vstack and used to layout the form fields rx.flex( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), rx.flex( rx.dialog.close( rx.button( "Cancel", variant="soft", color_scheme="gray", ), ), rx.dialog.close( rx.button("Submit", type="submit"), ), spacing="3", justify="end", ), direction="column", spacing="4", ), on_submit=State3.add_user, reset_on_submit=False, ), # max_width is used to limit the width of the dialog max_width="450px", ), ) ``` At this point we have an app that allows you to add users to a table by filling out a form. The form is placed in a dialog that can be opened by clicking the "Add User" button. We change the name of the component from `form` to `add_customer_button` and update this in our `index` component. The full app so far and code are below. ```python exec def add_customer_button() -> rx.Component: return rx.dialog.root( rx.dialog.trigger( rx.button( rx.icon("plus", size=26), rx.text("Add User", size="4"), ), ), rx.dialog.content( rx.dialog.title( "Add New User", ), rx.dialog.description( "Fill the form with the user's info", ), rx.form( rx.flex( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), rx.flex( rx.dialog.close( rx.button( "Cancel", variant="soft", color_scheme="gray", ), ), rx.dialog.close( rx.button("Submit", type="submit"), ), spacing="3", justify="end", ), direction="column", spacing="4", ), on_submit=State3.add_user, reset_on_submit=False, ), max_width="450px", ), ) ``` ```python eval rx.vstack( add_customer_button(), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State3.users, show_user), ), variant="surface", size="3", ), spacing="4", border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", padding="2em", ) ``` ```python @dataclasses.dataclass class User: """The user model.""" name: str email: str gender: str class State(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] def add_user(self, form_data: dict): self.users.append(User(**form_data)) def show_user(user: User): """Show a person in a table row.""" return rx.table.row( rx.table.cell(user.name), rx.table.cell(user.email), rx.table.cell(user.gender), ) def add_customer_button() -> rx.Component: return rx.dialog.root( rx.dialog.trigger( rx.button( rx.icon("plus", size=26), rx.text("Add User", size="4"), ), ), rx.dialog.content( rx.dialog.title( "Add New User", ), rx.dialog.description( "Fill the form with the user's info", ), rx.form( rx.flex( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), rx.flex( rx.dialog.close( rx.button( "Cancel", variant="soft", color_scheme="gray", ), ), rx.dialog.close( rx.button("Submit", type="submit"), ), spacing="3", justify="end", ), direction="column", spacing="4", ), on_submit=State.add_user, reset_on_submit=False, ), max_width="450px", ), ) def index() -> rx.Component: return rx.vstack( add_customer_button(), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State.users, show_user), ), variant="surface", size="3", ), ) ``` ## Plot a graph Next we'll plot the user data in a graph using Reflex's built-in recharts library, counting users by gender. ### Transform the data The graphing components in Reflex expect to take in a list of dictionaries. Each dictionary represents a data point on the graph and contains the x and y values. We will create a new event handler in the state called `transform_data` to transform the user data into the format that the graphing components expect. We must also create a new state variable called `users_for_graph` to store the transformed data, which will be used to render the graph. ```python from collections import Counter class State(rx.State): users: list[User] = [] users_for_graph: list[dict] = [] def add_user(self, form_data: dict): self.users.append(User(**form_data)) self.transform_data() def transform_data(self): """Transform user gender group data into a format suitable for visualization in graphs.""" # Count users of each gender group gender_counts = Counter(user.gender for user in self.users) # Transform into list of dict so it can be used in the graph self.users_for_graph = [ {"name": gender_group, "value": count} for gender_group, count in gender_counts.items() ] ``` As we can see above the `transform_data` event handler uses the `Counter` class from the `collections` module to count the number of users of each gender. We then create a list of dictionaries from this which we set to the state var `users_for_graph`. Finally we can see that whenever we add a new user through submitting the form and running the `add_user` event handler, we call the `transform_data` event handler to update the `users_for_graph` state variable. ### Render the graph We use the `rx.recharts.bar_chart` component to render the graph. We pass through the state variable for our graphing data as `data=State.users_for_graph`. We also pass in a `rx.recharts.bar` component which represents the bars on the graph. The `rx.recharts.bar` component takes in the `data_key` prop which is the key in the data dictionary that represents the y value of the bar. The `stroke` and `fill` props are used to set the color of the bars. The `rx.recharts.bar_chart` component also takes in `rx.recharts.x_axis` and `rx.recharts.y_axis` components which represent the x and y axes of the graph. The `data_key` prop of the `rx.recharts.x_axis` component is set to the key in the data dictionary that represents the x value of the bar. Finally we add `width` and `height` props to set the size of the graph. ```python def graph(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="value", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=State.users_for_graph, width="100%", height=250, ) ``` Finally we add this `graph()` component to our `index()` component so that the graph is rendered on the page. The code for the full app with the graph included is below. If you try this out you will see that the graph updates whenever you add a new user to the table. ```python exec from collections import Counter class State4(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] users_for_graph: list[dict] = [] def add_user(self, form_data: dict): self.users.append(User(**form_data)) self.transform_data() return rx.toast.info( f"User {form_data['name']} has been added.", position="bottom-right", ) def transform_data(self): """Transform user gender group data into a format suitable for visualization in graphs.""" # Count users of each gender group gender_counts = Counter(user.gender for user in self.users) # Transform into list of dict so it can be used in the graph self.users_for_graph = [ {"name": gender_group, "value": count} for gender_group, count in gender_counts.items() ] def add_customer_button() -> rx.Component: return rx.dialog.root( rx.dialog.trigger( rx.button( rx.icon("plus", size=26), rx.text("Add User", size="4"), ), ), rx.dialog.content( rx.dialog.title( "Add New User", ), rx.dialog.description( "Fill the form with the user's info", ), rx.form( rx.flex( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="Male", name="gender", ), rx.flex( rx.dialog.close( rx.button( "Cancel", variant="soft", color_scheme="gray", ), ), rx.dialog.close( rx.button("Submit", type="submit"), ), spacing="3", justify="end", ), direction="column", spacing="4", ), on_submit=State4.add_user, reset_on_submit=False, ), max_width="450px", ), ) def graph(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="value", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=State4.users_for_graph, width="100%", height=250, ) ``` ```python eval rx.vstack( add_customer_button(), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State4.users, show_user), ), variant="surface", size="3", ), graph(), spacing="4", border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", padding="2em", ) ``` ```python from collections import Counter class State(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] users_for_graph: list[dict] = [] def add_user(self, form_data: dict): self.users.append(User(**form_data)) self.transform_data() def transform_data(self): """Transform user gender group data into a format suitable for visualization in graphs.""" # Count users of each gender group gender_counts = Counter(user.gender for user in self.users) # Transform into list of dict so it can be used in the graph self.users_for_graph = [ {"name": gender_group, "value": count} for gender_group, count in gender_counts.items() ] def show_user(user: User): """Show a person in a table row.""" return rx.table.row( rx.table.cell(user.name), rx.table.cell(user.email), rx.table.cell(user.gender), ) def add_customer_button() -> rx.Component: return rx.dialog.root( rx.dialog.trigger( rx.button( rx.icon("plus", size=26), rx.text("Add User", size="4"), ), ), rx.dialog.content( rx.dialog.title( "Add New User", ), rx.dialog.description( "Fill the form with the user's info", ), rx.form( rx.flex( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="male", name="gender", ), rx.flex( rx.dialog.close( rx.button( "Cancel", variant="soft", color_scheme="gray", ), ), rx.dialog.close( rx.button("Submit", type="submit"), ), spacing="3", justify="end", ), direction="column", spacing="4", ), on_submit=State.add_user, reset_on_submit=False, ), max_width="450px", ), ) def graph(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="value", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=State.users_for_graph, width="100%", height=250, ) def index() -> rx.Component: return rx.vstack( add_customer_button(), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State.users, show_user), ), variant="surface", size="3", ), graph(), ) ``` If you run the app locally with no seed users, the graph is empty until you add one — `transform_data` only runs when a user is added. The next section fixes that by calling it on page load. ## Customize ### Revisit `app.add_page` At the beginning of this tutorial we mentioned that the `app.add_page` function is required for every Reflex app. This function is used to add a component to a page. The `app.add_page` currently looks like this `app.add_page(index)`. We could change the route that the page renders on by setting the `route` prop such as `route="/custom-route"`, this would change the route to `http://localhost:3000/custom-route` for this page. We can also set a `title` to be shown in the browser tab and a `description` as shown in search results. To solve the problem we had above about our graph not loading when the page loads, we can use `on_load` inside of `app.add_page` to call the `transform_data` event handler when the page loads. This would look like `on_load=State.transform_data`. Below see what our `app.add_page` would look like with some of the changes above added. ```python eval rx.vstack( add_customer_button(), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State4.users, show_user), ), variant="surface", size="3", ), graph(), on_mouse_enter=State4.transform_data, spacing="4", border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", padding="2em", ) ``` ```python app.add_page( index, title="Customer Data App", description="A simple app to manage customer data.", on_load=State.transform_data, ) ``` ### Revisit `rx.App()` At the beginning of the tutorial we also mentioned that we defined our app using `app=rx.App()`. We can also pass in some props to the `rx.App` component to customize the app. The most important one is `theme` which allows you to customize the look and feel of the app. The `theme` prop takes in an `rx.theme` component which has several props that can be set. The `radius` prop sets the global radius value for the app that is inherited by all components that have a `radius` prop. It can be overwritten locally for a specific component by manually setting the `radius` prop. The `accent_color` prop sets the accent color of the app. See the [theme docs](/docs/library/other/theme) for the full list of options. To see other props that can be set at the app level check out this [documentation](/docs/styling/theming) ```python app = rx.App( theme=rx.theme(radius="full", accent_color="grass"), ) ``` The theme applies at the app level, so you'll need to run locally to see it in action. ## Full app styled Finally let's make some styling updates. We will add hover styling to the table rows and center the table inside `show_user` with `style={"_hover": {"bg": rx.color("gray", 3)}}, align="center"`. In addition, we will add some `width="100%"` and `align="center"` to the `index()` component to center the items on the page and ensure they stretch the full width of the page. Check out the full code and interactive app below: ```python eval rx.box( rx.vstack( rx.hstack( rx.vstack( rx.text( "Users", size="4", weight="bold", color=rx.color("slate", 12), text_align="left", width="100%", ), rx.text( "Add customers and watch the chart update.", size="2", color=rx.color("slate", 10), text_align="left", width="100%", ), spacing="1", align="start", ), rx.spacer(), add_customer_button5(), align="center", width="100%", ), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State5.users, show_user5), ), variant="surface", size="2", width="100%", ), graph5(), align="stretch", width="100%", on_mouse_enter=State5.transform_data, spacing="4", padding="1.75em 2em", ), border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", margin_y="1em", background=rx.color("slate", 1), ) ``` ```python import reflex as rx from collections import Counter @dataclasses.dataclass class User: """The user model.""" name: str email: str gender: str class State(rx.State): users: list[User] = [ User(name="Danilo Sousa", email="danilo@example.com", gender="Male"), User(name="Zahra Ambessa", email="zahra@example.com", gender="Female"), ] users_for_graph: list[dict] = [] def add_user(self, form_data: dict): self.users.append(User(**form_data)) self.transform_data() def transform_data(self): """Transform user gender group data into a format suitable for visualization in graphs.""" # Count users of each gender group gender_counts = Counter(user.gender for user in self.users) # Transform into list of dict so it can be used in the graph self.users_for_graph = [ {"name": gender_group, "value": count} for gender_group, count in gender_counts.items() ] def show_user(user: User): """Show a user in a table row.""" return rx.table.row( rx.table.cell(user.name), rx.table.cell(user.email), rx.table.cell(user.gender), style={"_hover": {"bg": rx.color("gray", 3)}}, align="center", ) def add_customer_button() -> rx.Component: return rx.dialog.root( rx.dialog.trigger( rx.button( rx.icon("plus", size=26), rx.text("Add User", size="4"), ), ), rx.dialog.content( rx.dialog.title( "Add New User", ), rx.dialog.description( "Fill the form with the user's info", ), rx.form( rx.flex( rx.input(placeholder="User Name", name="name", required=True), rx.input( placeholder="user@reflex.dev", name="email", ), rx.select( ["Male", "Female"], placeholder="male", name="gender", ), rx.flex( rx.dialog.close( rx.button( "Cancel", variant="soft", color_scheme="gray", ), ), rx.dialog.close( rx.button("Submit", type="submit"), ), spacing="3", justify="end", ), direction="column", spacing="4", ), on_submit=State.add_user, reset_on_submit=False, ), max_width="450px", ), ) def graph(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="value", fill=rx.color("accent", 9), radius=6, bar_size=48, ), rx.recharts.x_axis( data_key="name", tick_line=False, axis_line=False, padding={"left": 24, "right": 24}, ), rx.recharts.y_axis( tick_line=False, axis_line=False, allow_decimals=False, ), rx.recharts.cartesian_grid( stroke_dasharray="3 3", vertical=False, stroke=rx.color("slate", 4), ), data=State.users_for_graph, width="100%", height=200, margin={"top": 8, "right": 8, "bottom": 0, "left": 0}, ) def index() -> rx.Component: return rx.box( rx.vstack( rx.hstack( rx.vstack( rx.text( "Users", size="4", weight="bold", color=rx.color("slate", 12), text_align="left", width="100%", ), rx.text( "Add customers and watch the chart update.", size="2", color=rx.color("slate", 10), text_align="left", width="100%", ), spacing="1", align="start", ), rx.spacer(), add_customer_button(), align="center", width="100%", ), rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Email"), rx.table.column_header_cell("Gender"), ), ), rx.table.body( rx.foreach(State.users, show_user), ), variant="surface", size="2", width="100%", ), graph(), align="stretch", width="100%", spacing="4", padding="1.75em 2em", ), border=f"1px solid {rx.color('slate', 5)}", border_radius="12px", margin_y="1em", background=rx.color("slate", 1), ) app = rx.App( theme=rx.theme(radius="full", accent_color="grass"), ) app.add_page( index, title="Customer Data App", description="A simple app to manage customer data.", on_load=State.transform_data, ) ``` ## Recap You built: - A table that displays user data. - A form (inside a dialog) to add new users. - A bar chart that visualizes the distribution. Along the way you learned: - **State** — how to store data that changes over time. - **Events** — how to respond to user actions and update the UI. - **Styling** — tweaking theme, layout, and hover states. # Installation Source: http://localhost:3000/docs/getting-started/installation.md ~3 minutes · Requires Python 3.10+. ## Virtual Environment We recommend [uv](https://docs.astral.sh/uv/) as the default; [venv](https://docs.python.org/3/library/venv.html), [conda](https://conda.io/), and [poetry](https://python-poetry.org/) are alternatives. ## Install Reflex on your system `````md tabs ## macOS/Linux ### Install uv ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` After installation, restart your terminal or run `source ~/.bashrc` (or `source ~/.zshrc` for zsh). Alternatively, install via [Homebrew, PyPI, or other methods](https://docs.astral.sh/uv/getting-started/installation/). ```md alert warning # macOS (Apple Silicon) users: install Rosetta 2 Run `/usr/sbin/softwareupdate --install-rosetta --agree-to-license`. See [Apple's instructions](https://support.apple.com/en-us/HT211861) for details. ``` ### Set up the Reflex project Replace `` with your project name, then switch into the new directory. ```bash mkdir cd uv init uv add reflex uv run reflex init ``` ## Windows For Windows users, we recommend [WSL](https://learn.microsoft.com/en-us/windows/wsl/about) for optimal performance — WSL users should follow the macOS/Linux tab; the rest of this section covers native Windows. ### Install uv ```powershell powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" ``` After installation, restart your terminal (PowerShell or Command Prompt). Alternatively, install via [WinGet, Scoop, or other methods](https://docs.astral.sh/uv/getting-started/installation/). ### Set up the Reflex project Replace `` with your project name, then switch into the new directory. ```powershell mkdir cd uv init uv add reflex uv run reflex init ``` ```md alert warning # Error `Install Failed - You are missing a DLL required to run bun.exe` Windows Bun requires runtime components of Visual C++ libraries to run on Windows. This issue is fixed by installing [Microsoft Visual C++ 2015 Redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=53840). ``` ````` Running `uv run reflex init` will return the option to start with a blank Reflex app, premade templates built by the Reflex team, or to try our [AI builder](https://build.reflex.dev/). ```bash Initializing the web directory. Get started with a template: (0) A blank Reflex app. (1) Premade templates built by the Reflex team. (2) Try our AI builder. Which template would you like to use? (0): ``` If this is your first time, pick **(0) A blank Reflex app** — the rest of the docs assume you started there. ## Run the App Run it in development mode: ```bash uv run reflex run ``` Your app runs at [http://localhost:3000](http://localhost:3000). Reflex _hot reloads_ any code changes in real time — your edits show up automatically. For troubleshooting, increase log verbosity with the `--loglevel` flag: ```bash uv run reflex run --loglevel debug ``` ```md alert info # Next: Build your first app Reflex is installed. The [Introduction](/docs/getting-started/introduction) walks through a working counter app in pure Python — the shortest path from "it runs" to "I understand it." ``` # Introduction Source: http://localhost:3000/docs/getting-started/introduction.md ```python exec import reflex as rx ``` **~5 min** · **Reflex** lets you build and deploy full-stack web apps — frontend, backend, and database — in **pure Python**. No JavaScript, no separate API, no context switching. ## Goals ```md section ### Pure Python Write your entire app — frontend, backend, database — in Python. No need to learn another language. ### Easy to Learn Ship your first app in minutes. No web development experience required. ### Full Flexibility Build anything from small data apps to large multi-page websites. **This entire site was built and deployed with Reflex.** ### Batteries Included One tool covers it all: UI, server-side logic, and deployment. ``` ## Build a counter We'll build a counter app that lets the user count up or down. In ~20 lines of Python you'll touch the three core pieces of every Reflex app: **state**, **event handlers**, and **components**. ```python exec class CounterExampleState(rx.State): count: int = 0 @rx.event def increment(self): self.count += 1 @rx.event def decrement(self): self.count -= 1 class IntroTabsState(rx.State): """The app state.""" value: str = "tab1" tab_selected: str = "" @rx.event def change_value(self, val: str): self.tab_selected = f"{val} clicked!" self.value = val def counter_code_section(code: str, tab: str) -> rx.Component: active = IntroTabsState.value == tab return rx.box( rx.code_block( code, class_name="code-block counter-code-block", ), background=rx.cond(active, "var(--c-violet-3)", "transparent"), border_left=rx.cond( active, "3px solid var(--c-violet-9)", "3px solid transparent", ), padding="0.875rem 1.5rem", class_name="w-full transition-colors", ) def counter_code_gap() -> rx.Component: return rx.box(height="0.875rem", flex_shrink="0") def tabs(): return rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Frontend", value="tab1", class_name="pill-tab"), rx.tabs.trigger("Backend", value="tab2", class_name="pill-tab"), rx.tabs.trigger("Page", value="tab3", class_name="pill-tab"), class_name="pill-tab-list", ), rx.tabs.content( rx.markdown( """The frontend is built declaratively with Reflex components, which compile to JS and run in the browser. Use `rx.cond` and `rx.foreach` instead of `if` and `for` for dynamic UIs. Any non-UI logic belongs in `State`. """, ), value="tab1", class_name="pt-4", ), rx.tabs.content( rx.markdown( """Write your backend in the `State` class. Here you can define functions and variables that can be referenced in the frontend. This code runs directly on the server and is not compiled, so there are no special caveats. Here you can use any Python external library and call any method/function. """, ), value="tab2", class_name="pt-4", ), rx.tabs.content( rx.markdown( """Each page is a Python function returning a Reflex component. Add as many as you want and link between them — see [Routing](/docs/pages/overview) for details. """, ), value="tab3", class_name="pt-4", ), class_name="text-slate-12 font-normal", default_value="tab1", value=IntroTabsState.value, on_change=lambda x: IntroTabsState.change_value(x), ) ``` ```python demo box id=counter rx.hstack( rx.button( "Decrement", color_scheme="ruby", on_click=CounterExampleState.decrement, ), rx.heading(CounterExampleState.count, font_size="2em"), rx.button( "Increment", color_scheme="grass", on_click=CounterExampleState.increment, ), spacing="4", ) ``` Here is the full code for this example: ```python eval tabs() ``` ```python eval rx.box( counter_code_section("""import reflex as rx """, ""), counter_code_gap(), counter_code_section( """class State(rx.State): count: int = 0 @rx.event def increment(self): self.count += 1 @rx.event def decrement(self): self.count -= 1""", "tab2", ), counter_code_gap(), counter_code_section( """def index(): return rx.hstack( rx.button( "Decrement", color_scheme="ruby", on_click=State.decrement, ), rx.heading(State.count, font_size="2em"), rx.button( "Increment", color_scheme="grass", on_click=State.increment, ), spacing="4", )""", "tab1", ), counter_code_gap(), counter_code_section( """app = rx.App() app.add_page(index)""", "tab3", ), class_name=( "w-full flex flex-col overflow-hidden rounded-xl border " "border-slate-4 bg-slate-2 py-1" ), ) ``` ## The Structure of a Reflex App Let's break this example down. ### Import ```python import reflex as rx ``` Import Reflex as `rx`. All Reflex objects are accessed as `rx.*`. ### State ```python class State(rx.State): count: int = 0 ``` State holds the app's mutable data. Variables declared here are called **[vars](/docs/vars/base-vars)**. Our counter has one: `count`, starting at `0`. ### Event Handlers ```python @rx.event def increment(self): self.count += 1 @rx.event def decrement(self): self.count -= 1 ``` **Event handlers** are the only way to modify state. They're triggered by user actions (clicks, typing, etc.) — those actions are called **events**. Our counter has two handlers: `increment` and `decrement`. ### User Interface (UI) ```python def index(): return rx.hstack( rx.button( "Decrement", color_scheme="ruby", on_click=State.decrement, ), rx.heading(State.count, font_size="2em"), rx.button( "Increment", color_scheme="grass", on_click=State.increment, ), spacing="4", ) ``` The UI is built from components (`rx.hstack`, `rx.button`, `rx.heading`) that can be nested and styled with CSS or [Tailwind](/docs/styling/tailwind). Reflex ships with [50+ built-in components](/docs/library), and you can [wrap any React component](/docs/wrapping-react/overview). Components reference state vars (`rx.heading(State.count, …)`) and reactively re-render when state changes. Event triggers (`on_click=State.decrement`) wire UI to handlers. The sequence goes like this: 1. User clicks "Increment". 2. `on_click` fires. 3. `State.increment` runs on the server. 4. `State.count` is updated. 5. UI re-renders with the new value. ### Add pages ```python app = rx.App() app.add_page(index) ``` Create the app and register the page at the base route. ## Next Steps 🎉 You've built a fully interactive web app in pure Python. ```md alert info # Keep learning - [Dashboard tutorial](/docs/getting-started/dashboard-tutorial/) — build a real data app. - [Chatapp tutorial](/docs/getting-started/chatapp-tutorial/) — wire up streaming AI responses. - [How Reflex works](/docs/advanced-onboarding/how-reflex-works/) — what happens under the hood. ``` ```md alert info # Ship faster with AI - [Reflex Build](https://build.reflex.dev/) — generate a full app from a prompt. - [Reflex Cloud](/docs/hosting/deploy-quick-start/) — one-command deploy. ``` Browse our [open-source templates](/docs/getting-started/open-source-templates/), or press `Cmd+K` / `Ctrl+K` to search the docs. # Open Source Templates Source: http://localhost:3000/docs/getting-started/open-source-templates.md Check out what the community is building with Reflex. See 2000+ more public projects on [Github](https://github.com/reflex-dev/reflex/network/dependents). Want to get your app featured? Submit it [here](https://github.com/reflex-dev/templates). Copy the template command and use it during `reflex init` ```python exec import reflex as rx from reflex_site_shared.components.code_card import gallery_app_card from reflex_site_shared.gallery.sidebar import TemplatesState, pagination, sidebar @rx.memo def skeleton_card() -> rx.Component: return rx.skeleton( class_name="box-border shadow-large border rounded-xl w-full h-[280px] overflow-hidden", loading=True, ) def component_grid() -> rx.Component: from reflex_site_shared.gallery.apps import gallery_apps_data posts = [] for path, document in list(gallery_apps_data.items()): posts.append( rx.cond( TemplatesState.filtered_templates.contains(document.metadata["title"]), gallery_app_card(app=document.metadata), None, ) ) return rx.box( *posts, rx.box( rx.el.h4( "No templates found", class_name="text-base font-semibold text-slate-12 text-nowrap", ), class_name="flex-col gap-2 flex absolute left-1 top-0 z-[-1] w-full", ), class_name="gap-6 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 w-full relative", ) def gallery() -> rx.Component: return rx.el.section( rx.box( sidebar(), rx.box( component_grid(), pagination(), class_name="flex flex-col", ), class_name="flex flex-col gap-6 lg:gap-10 w-full", ), id="gallery", class_name="mx-auto", ) ``` ```python eval gallery() ``` # Project Structure Source: http://localhost:3000/docs/getting-started/project-structure.md ## Directory Structure Let's create a new app called `hello` ```bash mkdir hello cd hello uv init uv add reflex uv run reflex init ``` This will create a directory structure like this: ```bash hello ├── .venv ├── .web ├── assets ├── hello │ ├── __init__.py │ └── hello.py ├── .gitignore ├── .python-version ├── pyproject.toml ├── rxconfig.py └── uv.lock ``` `uv init` may also create helper files such as `README.md`, `main.py`, and Git metadata. The tree above focuses on the main files you will interact with while building a Reflex app. Let's go over each of these directories and files. ## .venv `uv add reflex` creates a local virtual environment in `.venv` by default. This keeps your app dependencies isolated from the rest of your system Python. ## .web This is where the compiled Javascript files will be stored. You will never need to touch this directory, but it can be useful for debugging. Each Reflex page will compile to a corresponding `.js` file in the `.web/pages` directory. ## Assets The `assets` directory is where you can store any static assets you want to be publicly available. This includes images, fonts, and other files. For example, if you save an image to `assets/image.png` you can display it from your app like this: ```python rx.image(src="https://web.reflex-assets.dev/other/image.png") ``` ## Main Project Initializing your project creates a directory with the same name as your app. This is where you will write your app's logic. Reflex generates a default app within the `hello/hello.py` file. You can modify this file to customize your app. ## Python Project Files `pyproject.toml` defines your Python project metadata and dependencies. `uv add reflex` records the Reflex dependency there before you initialize the app. `uv.lock` stores the fully resolved dependency set for reproducible installs. Commit it to version control so everyone working on the app gets the same Python package versions. ## Configuration The `rxconfig.py` file can be used to configure your app. By default it looks something like this: ```python import reflex as rx config = rx.Config( app_name="hello", ) ``` We will discuss project structure and configuration in more detail in the [advanced project structure](/docs/advanced-onboarding/code-structure) documentation. # Project Source: http://localhost:3000/docs/hosting/adding-members.md ```python exec import reflex as rx ``` A project is a collection of applications (apps / websites). Every project has its own billing page that are accessible to Admins. ## Adding Team Members To see the team members of a project click on the `Members` tab in the Cloud UI on the project page. If you are a User you have the ability to create, deploy and delete apps, but you do not have the power to add or delete users from that project. You must be an Admin for that. As an Admin you will see the an `Add user` button in the top right of the screen, as shown in the image below. Clicking on this will allow you to add a user to the project. You will need to enter the email address of the user you wish to add. ```python eval rx.image( src="https://web.reflex-assets.dev/other/hosting_adding_team_members.webp", alt="Adding team members to Reflex Cloud", ) ``` ```python eval rx.box(height="20px") ``` ```md alert warning # Currently a User must already have logged in once before they can be added to a project. At this time a User must be logged in to be added to a project. In future there will be automatic email invites sent to add new users who have never logged in before. ``` ## Other project settings Clicking on the `Settings` tab in the Cloud UI on the project page allows a user to change the `project name`, check the `project id` and, if the project is not your default project, delete the project. # App Source: http://localhost:3000/docs/hosting/app-management.md ```python exec import reflex as rx ``` In Reflex Cloud an "app" (or "application" or "website") refers to a web application built using the Reflex framework, which can be deployed and managed within the Cloud platform. You can deploy an app using the `reflex deploy` command. There are many actions you can take in the Cloud UI to manage your app. Below are some of the most common actions you may want to take. ## Stopping an App To stop an app follow the arrow in the image below and press on the `Stop app` button. Pausing an app will stop it from running and will not be accessible to users until you resume it. In addition, this will stop you being billed for your app. ```python eval rx.image( src="https://web.reflex-assets.dev/other/stopping_app.webp", padding_bottom="20px" ) ``` ```md alert info # CLI Command to stop an app `reflex cloud apps stop [OPTIONS] [APP_ID]` ``` ## Deleting an App To delete an app click on the `Settings` tab in the Cloud UI on the app page. ```python eval rx.image(src="https://web.reflex-assets.dev/other/environment_variables.webp") ``` Then click on the `Danger` tab as shown below. ```python eval rx.image(src="https://web.reflex-assets.dev/other/deleting_app.webp") ``` Here there is a `Delete app` button. Pressing this button will delete the app and all of its data. This action is irreversible. ```md alert info # CLI Command to delete an app `reflex cloud apps delete [OPTIONS] [APP_ID]` ``` ## Other app settings Clicking on the `Settings` tab in the Cloud UI on the app page also allows a user to change the `app name`, change the `app description` and check the `app id`. The other app settings also allows users to edit and add secrets (environment variables) to the app. For more information on secrets, see the [Secrets (Environment Variables)](/docs/hosting/secrets-environment-vars/) page. # Billing Source: http://localhost:3000/docs/hosting/billing.md ```python exec import reflex as rx ``` ## Overview Billing for Reflex Cloud is monthly per project. Project owners and admins are able to view and manage the billing page. The billing for a project is comprised of two parts - number of `seats` and `compute`. ## Seats Projects on a paid plan can invite collaborators to join their project. Each additional collaborator is considered a `seat` and is charged on a flat monthly rate. Project owners and admins can manage permissions and roles for each seat in the settings tab on the project page. ## Compute Reflex Cloud is billed on a per second basis so you only pay for when your app is being used by your end users. When your app is idle, you are not charged. For more information on compute pricing, please see the [compute](/docs/hosting/compute/) page. ## Manage Billing To manage your billing, you can go to the `Billing` tab in the Cloud UI on the project page. ## Setting Billing Limits If you want to set a billing limit for your project, you can do so by going to the `Billing` tab in the Cloud UI on the project page. # Compute Source: http://localhost:3000/docs/hosting/compute.md ```python exec import reflex as rx ``` ## Compute Usage Reflex Cloud is billed on a per second basis so you only pay for when your app is being used by your end users. When your app is idle, you are not charged. This allows you to deploy your app on larger sizes and multiple regions without worrying about paying for idle compute. We bill on a per second basis so you only pay for the compute you use. By default your app stays alive for 5 minutes after the no users are connected. After this time your app will be considered idle and you will not be charged. Start up times usually take less than 1 second for you apps to come back online. #### Warm vs Cold Start - Apps below `c2m2` are considered warm starts and are usually less than 1 second. - If your app is larger than `c2m2` it will be a cold start which takes around 15 seconds. If you want to avoid this you can reserve a machine. ## Reserved Machines (Coming Soon) If you expect your apps to be continuously receiving users, you may want to reserve a machine instead of having us manage your compute. This will be a flat monthly rate for the machine. ## Monitoring Usage To monitor your projects usage, you can go to the billing tab in the Reflex Cloud UI on the project page. Here you can see the current billing and usage for your project. ## Real Life Examples of compute charges on the paid tiers ```md alert # Single Application - Single Region Anna, a hobbyist game developer, built a pixel art generator and hosted it on Reflex Cloud so fellow artists could use it anytime. She deployed her app in the San Francisco region, where she lives. If her users use the site for an hour a day, how much would Anna pay? **Facts:** - **Machine size:** `c1m1` (1 CPU, 1 GB Memory) - `$0.083` per hour - **Regions:** `1` (SJC) - **Avg usage per day per region:** `1 Hour` **Maths:** `1 region * 1 hour * 30 days = 30 compute hours` `30 * 0.083 = 2.49` (assuming a 30 day month) Anna's total cost for compute would be `$2.49` for the month. However, since paid users receive a `$10` credit, her compute cost is fully covered. **Charge for compute:** `$0.00 dollars` ``` ```md alert # Single Application - Multi Region Bob created a social media application and decided to host it on Reflex Cloud. Bob has users in Paris, London, San Jose and Sydney. Bob decided to deploy his application to all those region as well as additional one in Paris since that where Bob lives. If users use the site in each region for 30 minutes a day how much would Bob pay? **Facts:** - **Machine size:** `c1m1` (1 CPU, 1 GB Memory) - `$0.083` Cost per hour - **Regions:** `5` (CDG x 2, LHR x 1, SJC x 1, SYD x 1) - **Avg usage per day per region:** `0.5 Hours` **Maths:** `5 regions * 0.5 hours * 30 days = 75 compute hours` `75 * 0.083 = 6.23` (assuming a 30 day month) Bob would owe `$6.23` for this month. However since Bob is a paid user they receive a `$10` credit which brings Bob's bill down to `$0`. **Charge for compute:** `$0.00 dollars` ``` ```md alert # Single Growing Application - Multi Region Charlie, a small startup founder, built a finance tracking app that allows users to create and share finance insights in real time. As his user base expanded across different regions, he needed a multi-region setup to reduce latency and improve performance. To ensure a smooth experience, he deployed his app on Reflex Cloud using a `c1m2` machine in four regions. If users access the app on average for **16 hours per week** in each region, how much would Charlie pay? **Facts:** - **Machine size:** `c1m2` (1 CPU, 2 GB Memory) - `$0.157` per hour - **Regions:** `4` - **Avg usage per week per region:** `16 Hours` **Maths:** `4 regions * 16 hours * 4 weeks = 256 compute hours` `256 * 0.157 = 40.19` (assuming 4 weeks in a month) Charlie would owe `$40.19` for this month. However since Charlie is a paid user they receive a `$10` credit which brings Bob's bill down to `$30.19`. **Charge for compute:** `$30.19 dollars` ``` ```md alert # Single Application High-Performance App - Single Region David, an **AI enthusiast**, developed a **real-time image enhancement tool** that allows photographers to upscale and enhance their images using machine learning. Since his app requires more processing power, he deployed it on a **`c2m2` machine**, which offers increased CPU and memory to handle the intensive AI workloads. With users accessing the app **2 hours per day** over a **30-day month**, how much would David pay? **Facts:** - **Machine size:** `c2m2` (2 CPU, 2 GB Memory) - `$0.166` per hour - **Regions:** `1` - **Avg usage per day:** `2 Hours` **Maths:** `1 region * 2 hours * 30 days = 60 compute hours` `60 * 0.166 = 9.96` (assuming a 30 day month) David would owe `$9.96` for this month. However since David is a paid user they receive a `$10` credit, he will not be charged for compute for this month. **Charge for compute:** `$0.00 dollars` ``` ```md alert # Single Fast Scaling App - Multiple Regions Emily, a **productivity app developer**, built a **real-time team collaboration tool** that helps remote teams manage tasks and communicate efficiently. With users spread across multiple locations, she needed **low-latency performance** to ensure a seamless experience. To achieve this, Emily deployed her app using a `c1m1` machine in **three regions**. With users actively using the app **6 hours per day in each region** over a **30-day month**, how much would Emily pay? **Facts:** - **Machine size:** `c1m1` (1 CPU, 1 GB Memory) - `$0.083` per hour - **Regions:** `3` - **Avg usage per day per region:** `6 Hours` **Maths:** `3 regions * 6 hours * 30 days = 540 compute hours` `540 * 0.083 = 44.82` (assuming a 30 day month) Emily would owe `$44.82` for this month. However since Emily is a paid user they receive a `$10` credit which brings Emily's bill down to `$34.82`. **Charge for compute:** `$34.82 dollars` ``` ```md alert # Multiple Apps - Multiple Regions Fred, a **freelance developer**, built a **portfolio of web applications** that cater to different clients across the globe. He has built **5 apps** where **4 apps** have a small amount of traffic with an average of **0.5 hours a day** and **1 app** that has a high amount of traffic with an average of **6 hours** a day. He has deployed the 4 small traffic apps on a `c1m1` machine in **1 region** each and the high traffic app on a `c1m1` machine in **2 regions**. How much would Fred pay? **Facts for 4 small traffic apps:** - **Machine size:** `c1m1` (1 CPU, 1 GB Memory) - `$0.083` per hour - **Regions:** `1` - **Avg usage per day per region:** `0.5 Hours` **Facts for 1 large traffic app:** - **Machine size:** `c1m1` (1 CPU, 1 GB Memory) - `$0.083` per hour - **Regions:** `2` - **Avg usage per day per region:** `6 Hours` **Maths:** 4 small traffic apps: `4 apps * 1 region * 0.5 hours * 30 days = 60 compute hours` 1 large traffic apps: `2 regions * 6 hours * 30 days = 360 compute hours` Total compute hours = `60 + 360 = 420 compute hours` `420 * 0.083 = 34.86` (assuming a 30 day month) Fred would owe `$34.86` for this month. However since Fred is a paid user they receive a `$10` credit which brings Fred's bill down to `$24.86`. **Charge for compute:** `$24.82 dollars` ``` One thing that is important to note is that in the hypothetical example where you have `50 people` using your app `continuously for 24 hours` or if you have `1 person` using your app `continuously for 24 hours`, you `will be charged the same amount` as the charge is based on the amount of time your app up and not the number of users using your app. In `both these examples` your `app is up for 24 hours` and therefore you will be `charged for 24 hours of compute`. # Config File Source: http://localhost:3000/docs/hosting/config-file.md ```python exec import reflex as rx ``` ## What is reflex cloud config? The following command: ```bash reflex cloud config ``` generates a `cloud.yml` configuration file used to deploy your Reflex app to the Reflex cloud platform. This file tells Reflex how and where to run your app in the cloud. ## Configuration File Structure The `cloud.yml` file uses YAML format and supports the following structure. **All fields are optional** and will use sensible defaults if not specified: ```yaml # Basic deployment settings name: my-app-prod # Optional: defaults to project folder name description: 'Production deployment' # Optional: empty by default projectname: my-client-project # Optional: defaults to personal project # Infrastructure settings regions: # Optional: defaults to sjc: 1 sjc: 1 # San Jose (# of machines) lhr: 2 # London (# of machines) vmtype: c2m2 # Optional: defaults to c1m1 # Custom domain and environment hostname: myapp # Optional: myapp.reflex.dev envfile: .env.production # Optional: defaults to .env # Additional dependencies packages: # Optional: empty by default - procps ``` ## Configuration Options Reference ```python demo-only rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell( rx.text("Option", size="1", weight="bold", color=rx.color("slate", 11)) ), rx.table.column_header_cell( rx.text("Type", size="1", weight="bold", color=rx.color("slate", 11)) ), rx.table.column_header_cell( rx.text("Default", size="1", weight="bold", color=rx.color("slate", 11)) ), rx.table.column_header_cell( rx.text( "Description", size="1", weight="bold", color=rx.color("slate", 11) ) ), align="center", ) ), rx.table.body(*[ rx.table.row( rx.table.cell(rx.text(option, class_name="text-sm")), rx.table.cell(rx.text(type_, class_name="text-sm")), rx.table.cell(rx.text(default, class_name="text-sm")), rx.table.cell( rx.link(description, href=link, class_name="text-sm") if link else rx.text(description, size="1", weight="regular") ), align="center", ) for option, type_, default, description, link in [ ( "name", "string", "folder name", "Deployment identifier in dashboard", None, ), ("description", "string", "empty", "Description of deployment", None), ( "regions", "object", "sjc: 1", "Region deployment mapping", "/docs/hosting/regions", ), ( "vmtype", "string", "c1m1", "Virtual machine specifications", "/docs/hosting/machine-types", ), ("hostname", "string", "null", "Custom subdomain", None), ( "envfile", "string", ".env", "Environment variables file path", "/docs/hosting/secrets-environment-vars", ), ("project", "uuid", "null", "Project uuid", None), ("projectname", "string", "null", "Project name", None), ("packages", "array", "empty", "Additional system packages", None), ("include_db", "boolean", "false", "Include local sqlite", None), ("strategy", "string", "auto", "Deployment strategy", None), ] ]), variant="ghost", size="2", width="100%", max_width="800px", ) ``` ## Configuration Options For details of specific sections click the links in the table. ### Projects Organize deployments using projects: ```yaml projectname: client-alpha # Groups related deployments ``` You can also specify a project uuid instead of name: ```yaml project: 12345678-1234-1234-1234-1234567890ab ``` You can go to the homepage of the project in the reflex cloud dashboard to find your project uuid in the url `https://build.reflex.dev/project/uuid` ### Apt Packages Install additional system packages your application requires. Package names are based on the apt package manager: ```yaml packages: - procps=2.0.32-1 # Version pinning is optional - imagemagick - ffmpeg ``` ### Include SQLite Include local sqlite database: ```yaml include_db: true ``` This is not persistent and will be lost on restart. It is recommended to use a database service instead. ### Strategy Deployment strategy: Available strategies: - `immediate`: [Default] Deploy immediately - `rolling`: Deploy in a rolling manner - `bluegreen`: Deploy in a blue-green manner - `canary`: Deploy in a canary manner, boot as single machine verify its health and then restart the rest. ```yaml strategy: immediate ``` ## Multi-Environment Setup **Development (`cloud-dev.yml`):** ```yaml name: myapp-dev description: 'Development environment' vmtype: c1m1 envfile: .env.development ``` **Staging (`cloud-staging.yml`):** ```yaml name: myapp-staging description: 'Staging environment' regions: sjc: 1 vmtype: c2m2 envfile: .env.staging ``` **Production (`cloud-prod.yml`):** ```yaml name: myapp-production description: 'Production environment' regions: sjc: 2 lhr: 1 vmtype: c4m4 hostname: myapp envfile: .env.production ``` Deploy with specific configuration files: ```bash # Use default cloud.yml reflex deploy # Use specific configuration file reflex deploy --config cloud-prod.yml reflex deploy --config cloud-staging.yml ``` # Custom Domains Source: http://localhost:3000/docs/hosting/custom-domains.md ```python exec import reflex as rx ``` With the Enterprise tier of Reflex Cloud you can use your own custom domain to host your app. ## Prerequisites You must purchase a domain from a domain registrar such as GoDaddy, Cloudflare, Namecheap, or AWS. For this tutorial we will use GoDaddy and the example domain `tomgotsman.us`. ## Steps Once you have purchased your domain, you can add it to your Reflex Cloud app by following these steps: 1 - Ensure you have deployed your app to Reflex Cloud. 2 - Once your app is deployed click the `Custom Domain` tab and add your custom domain to the input field and press the Add domain button. You should now see a page like below: ```python eval rx.image(src="https://web.reflex-assets.dev/other/custom-domains-DNS-inputs.webp") ``` ```python eval rx.box(height="20px") ``` 3 - On the domain registrar's website, navigate to the DNS settings for your domain. It should look something like the image below: ```python eval rx.image(src="https://web.reflex-assets.dev/other/custom-domains-DNS-before.webp") ``` ```python eval rx.box(height="20px") ``` 4 - Add all four of the DNS records provided by Reflex Cloud to your domain registrar's DNS settings. If there is already an A name record, delete it and replace it with the one provided by Reflex Cloud. Your DNS settings should look like the image below: ```python eval rx.image(src="https://web.reflex-assets.dev/other/custom-domains-DNS-after.webp") ``` ```md alert warning # It may alert you that this record will resolve on ######.tomgotsman.us.tomgotsman.us. If this happens ensure that you select to only have the record resolve on ######.tomgotsman.us. ``` ```md alert warning # Your domain provider may not support an Apex CNAME record, in this case just use an A record. ![Image showing failed CNAME record](/custom-domains-CNAME-fail.png) ``` ```python eval rx.box(height="20px") ``` 5 - Once you have added the DNS records, refresh the page on the Reflex Cloud page (it may take a few minutes to a few hours to update successfully). If the records are correct, you should see a success message like the one below: ```python eval rx.image(src="https://web.reflex-assets.dev/other/custom-domains-success.webp") ``` ```python eval rx.box(height="20px") ``` 6 - Now redeploy your app using the `reflex deploy` command and your app should now be live on your custom domain! # Deploy Reflex to Databricks Source: http://localhost:3000/docs/hosting/databricks.md ```python exec import reflex as rx ``` This guide walks you through deploying a Reflex web application on Databricks using the Apps platform. ## Prerequisites - Databricks workspace with Unity Catalog enabled - GitHub repository containing your Reflex application - Reflex Enterprise license (for single-port deployment) ## Step 1: Connect Your Repository 1. **Link GitHub Repository** - Navigate to your Databricks workspace - Go to your user directory - Click **Create** → **Git folder** - Paste the URL of your GitHub repository containing the Reflex application ## Step 2: Configure Application Settings ### Create Configuration File Create a new file called `app.yaml` directly in Databricks (not in GitHub): ```yaml command: [ "reflex", "run", "--env", "prod", "--backend-port", "$DATABRICKS_APP_PORT" ] env: - name: "HOME" value: "/tmp/reflex" - name: "REFLEX_ACCESS_TOKEN" value: "your-token-here" - name: "DATABRICKS_WAREHOUSE_ID" value: "your-sql-warehouse-id" - name: "DATABRICKS_CATALOG" value: "your-catalog-name" - name: "DATABRICKS_SCHEMA" value: "your-schema-name" - name: "REFLEX_SHOW_BUILT_WITH_REFLEX" value: 0 ``` ### Obtain Required Tokens 1. **Reflex Access Token** - Visit [Reflex Cloud Tokens](https://build.reflex.dev/tokens/) - Navigate to Account Settings → Tokens - Create a new token and copy the value - Replace `your-token-here` in the configuration 2. **Databricks Resources** - Update `DATABRICKS_WAREHOUSE_ID` with your SQL warehouse ID - Update `DATABRICKS_CATALOG` with your target catalog name - Update `DATABRICKS_SCHEMA` with your target schema name ## Step 3: Enable Single-Port Deployment Update your Reflex application for Databricks compatibility: ### Update rxconfig.py ```python import reflex as rx import reflex_enterprise as rxe rxe.Config(app_name="app", use_single_port=True) ``` ### Update Application Entry Point Modify your main application file where you define `rx.App`: ```python import reflex_enterprise as rxe app = rxe.App( # your app configuration ) ``` ```md alert info # Also add `reflex-enterprise` and `asgiproxy` to your `requirements.txt` file. ``` ## Step 4: Create Databricks App 1. **Navigate to Apps** - Go to **Compute** → **Apps** - Click **Create App** 2. **Configure Application** - Select **Custom App** - Configure SQL warehouse for your application ## Step 5: Set Permissions If you are using the `samples` Catalog then you can skip the permissions section. ### Catalog Permissions 1. Navigate to **Catalog** → Select your target catalog 2. Go to **Permissions** 3. Add the app's service principal user 4. Grant the following permissions: - **USE CATALOG** - **USE SCHEMA** ### Schema Permissions 1. Navigate to the specific schema 2. Go to **Permissions** 3. Grant the following permissions: - **USE SCHEMA** - **EXECUTE** - **SELECT** - **READ VOLUME** (if required) ## Step 6: Deploy Application 1. **Initiate Deployment** - Click **Deploy** in the Apps interface - When prompted for the code path, provide your Git folder path or select your repository folder 2. **Monitor Deployment** - The deployment process will begin automatically - Monitor logs for any configuration issues ## Updating Your Application To deploy updates from your GitHub repository: 1. **Pull Latest Changes** - In the deployment interface, click **Deployment Source** - Select **main** branch - Click **Pull** to fetch the latest changes from GitHub 2. **Redeploy** - Click **Deploy** again to apply the updates ## Configuration Reference ```python eval rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Environment Variable"), rx.table.column_header_cell("Description"), rx.table.column_header_cell("Example"), ), ), rx.table.body( rx.table.row( rx.table.cell(rx.code("HOME")), rx.table.cell("Application home directory"), rx.table.cell(rx.code("/tmp/reflex")), ), rx.table.row( rx.table.cell(rx.code("REFLEX_ACCESS_TOKEN")), rx.table.cell("Authentication for Reflex Cloud"), rx.table.cell(rx.code("rx_token_...")), ), rx.table.row( rx.table.cell(rx.code("DATABRICKS_WAREHOUSE_ID")), rx.table.cell("SQL warehouse identifier"), rx.table.cell("Auto-assigned"), ), rx.table.row( rx.table.cell(rx.code("DATABRICKS_CATALOG")), rx.table.cell("Target catalog name"), rx.table.cell(rx.code("main")), ), rx.table.row( rx.table.cell(rx.code("DATABRICKS_SCHEMA")), rx.table.cell("Target schema name"), rx.table.cell(rx.code("default")), ), rx.table.row( rx.table.cell(rx.code("REFLEX_SHOW_BUILT_WITH_REFLEX")), rx.table.cell("Show Reflex branding (Enterprise only)"), rx.table.cell([rx.code("0"), " or ", rx.code("1")]), ), ), variant="surface", margin_y="1em", ) ``` ## Troubleshooting - **Permission Errors**: Verify that all catalog and schema permissions are correctly set - **Port Issues**: Ensure you're using `$DATABRICKS_APP_PORT` and single-port configuration - **Token Issues**: Verify your Reflex access token is valid and properly configured - **Deployment Failures**: Check the deployment logs for specific error messages ## Notes - Single-port deployment requires Reflex Enterprise - Configuration must be created directly in Databricks, not pushed from GitHub - Updates require manual pulling from the deployment interface # Reflex Cloud - Quick Start Source: http://localhost:3000/docs/hosting/deploy-quick-start.md ```python exec import reflex as rx ``` So far, we have been running our apps locally on our own machines. But what if we want to share our apps with the world? This is where the hosting service comes in. ## Quick Start Reflex’s hosting service makes it easy to deploy your apps without worrying about configuring the infrastructure. ### Prerequisites 1. Hosting service requires `reflex>=0.6.6`. 2. This tutorial assumes you have successfully `reflex init` and `reflex run` your app. 3. Also make sure you have a `requirements.txt` file at the top level app directory that contains all your python dependencies! (To create a `requirements.txt` file, run `pip freeze > requirements.txt`.) ### Authentication First run the command below to login / signup to your Reflex Cloud account: (command line) ```bash reflex login ``` You will be redirected to your browser where you can authenticate through Github or Gmail. ### Web UI Once you are at this URL and you have successfully authenticated, click on the one project you have in your workspace. You should get a screen like this: ```python eval rx.image( src="https://web.reflex-assets.dev/other/cloud_project_page.webp", alt="Reflex Cloud Dashboard", ) ``` This screen shows the login command and the deploy command. As we are already logged in, we can skip the login command. ### Deployment Now you can start deploying your app. In your cloud UI copy the `reflex deploy` command similar to the one shown below. ```bash reflex deploy --project 2a432b8f-2605-4753-####-####0cd1#### ``` In your project directory (where you would normally run `reflex run`) paste this command. The command is by default interactive. It asks you a few questions for information required for the deployment. 1. The first question will compare your `requirements.txt` to your python environment and if they are different then it will ask you if you want to update your `requirements.txt` or to continue with the current one. If they are identical this question will not appear. To create a `requirements.txt` file, run `pip freeze > requirements.txt`. 2. The second question will search for a deployed app with the name of your current app, if it does not find one then it will ask if you wish to proceed in deploying your new app. 3. The third question is optional and will ask you for an app description. That’s it! You should receive some feedback on the progress of your deployment and in a few minutes your app should be up. 🎉 For detailed information about the deploy command and its options, see the [Deploy API Reference](/docs/hosting/deploy-quick-start/) and the [CLI Reference](https://reflex.dev/docs/api-reference/cli/). ```md alert info # Once your code is uploaded, the hosting service will start the deployment. After a complete upload, exiting from the command **does not** affect the deployment process. The command prints a message when you can safely close it without affecting the deployment. ``` If you go back to the Cloud UI you should be able to see your deployed app and other useful app information. ```md alert info # Setup a Cloud Config File To create a `config.yml` file for your app to set your app configuration check out the [Cloud Config Docs](/docs/hosting/config-file/). ``` ```md alert info # Moving around the Cloud UI To go back, i.e. from an app to a project or from a project to your list of projects you just click the `REFLEX logo` in the top left corner of the page. ``` ```md alert info # All flag values are saved between runs All your flag values, i.e. environment variables or regions or tokens, are saved between runs. This means that if you run a command and you pass a flag value, the next time you run the same command the flag value will be the same as the last time you ran it. This means you should only set the flag values again if you want to change them. ``` # Deploy with Github Actions Source: http://localhost:3000/docs/hosting/deploy-with-github-actions.md ```python exec import reflex as rx code_style = { "color": rx.color("violet", 11), "border_radius": "0.25rem", "border": f"1px solid {rx.color('violet', 5)}", "background": rx.color("violet", 3), } cell_style = { "font_family": "Instrument Sans", "font_style": "normal", "font_weight": "500", "font_size": "14px", "line_height": "1.5", "letter_spacing": "-0.0125em", "color": "var(--c-slate-11)", } github_actions_configs = [ { "name": "auth_token", "description": "Reflex authentication token stored in GitHub Secrets.", "required": True, "default": "N/A", }, { "name": "project_id", "description": "The ID of the project you want to deploy to.", "required": True, "default": "N/A", }, { "name": "app_directory", "description": "The directory containing your Reflex app.", "required": False, "default": ". (root)", }, { "name": "extra_args", "description": "Additional arguments to pass to the `reflex deploy` command.", "required": False, "default": "N/A", }, { "name": "python_version", "description": "The Python version to use for the deployment environment.", "required": False, "default": "3.12", }, ] ``` This GitHub Action simplifies the deployment of Reflex applications to Reflex Cloud. It handles setting up the environment, installing the Reflex CLI, and deploying your app with minimal configuration. ```md alert info # This action requires `reflex>=0.6.6` ``` **Features:** - Deploy Reflex apps directly from your GitHub repository to Reflex Cloud. - Supports subdirectory-based app structures. - Securely uses authentication tokens via GitHub Secrets. ## Usage ### Add the Action to Your Workflow Create a `.github/workflows/deploy.yml` file in your repository and add the following: ```yaml name: Deploy Reflex App on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy to Reflex Cloud uses: reflex-dev/reflex-deploy-action@v1 with: auth_token: ${{ secrets.REFLEX_PROJECT_ID }} project_id: ${{ secrets.REFLEX_PROJECT_ID }} app_directory: "my-app-folder" # Optional, defaults to root extra_args: "--env THIRD_PARTY_APIKEY=***" # Optional python_version: "3.12" # Optional ``` ### Set Up Your Secrets Store your Reflex authentication token securely in your repository's secrets: 1. Go to your GitHub repository. 2. Navigate to Settings > Secrets and variables > Actions > New repository secret. 3. Create new secrets for `REFLEX_AUTH_TOKEN` and `REFLEX_PROJECT_ID`. (Create a `REFLEX_AUTH_TOKEN` in the tokens tab of your UI, check out these [docs](/docs/hosting/tokens/#tokens). The `REFLEX_PROJECT_ID` can be found in the UI when you click on the How to deploy button on the top right when inside a project and copy the ID after the `--project` flag.) ### Inputs ```python eval rx.table.root( rx.table.header( rx.table.row( rx.table.column_header_cell("Name"), rx.table.column_header_cell("Description"), rx.table.column_header_cell("required"), rx.table.column_header_cell("Default"), ), ), rx.table.body(*[ rx.table.row( rx.table.cell(rx.code(github_config["name"], style=code_style)), rx.table.cell(github_config["description"], style=cell_style), rx.table.cell(rx.code(github_config["required"], style=code_style)), rx.table.cell( rx.code(github_config["default"], style=code_style), min_width="100px" ), ) for github_config in github_actions_configs ]), variant="surface", ) ``` # Logs Source: http://localhost:3000/docs/hosting/logs.md ```python exec import reflex as rx ``` ## View Logs To view the app logs follow the arrow in the image below and press on the `Logs` dropdown. ```python eval rx.image( src="https://web.reflex-assets.dev/other/view_logs.webp", padding_bottom="20px" ) ``` ```md alert info # CLI Command to view logs `reflex cloud apps logs [OPTIONS] [APP_ID]` ``` ## View Deployment Logs and Deployment History To view the deployment history follow the arrow in the image below and press on the `Deployments`. ```python eval rx.image(src="https://web.reflex-assets.dev/other/view_deployment_logs.webp") ``` This brings you to the page below where you can see the deployment history of your app. Click on deployment you wish to explore further. ```python eval rx.image( src="https://web.reflex-assets.dev/other/view_deployment_logs_2.webp", padding_bottom="20px", ) ``` ```md alert info # CLI Command to view deployment history `reflex cloud apps history [OPTIONS] [APP_ID]` ``` This brings you to the page below where you can view the deployment logs of your app by clicking the `Build logs` dropdown. ```python eval rx.image(src="https://web.reflex-assets.dev/other/view_deployment_logs_3.webp") ``` # Machine Types Source: http://localhost:3000/docs/hosting/machine-types.md ```python exec import reflex as rx ``` ## Machine Types To scale your app you can choose different VMTypes. VMTypes are different configurations of CPU and RAM. To scale your VM in the Cloud UI, click on the `Settings` tab in the Cloud UI on the app page, and then click on the `Scale` tab as shown below. Clicking on the `Change VM` button will allow you to scale your app. ```python eval rx.image( src="https://web.reflex-assets.dev/other/scaling_vms.webp", padding_bottom="20px" ) ``` ### VMTypes in the CLI To get all the possible VMTypes you can run the following command: ```bash reflex cloud vmtypes ``` To set which VMType to use when deploying your app you can pass the `--vmtype` flag with the id of the VMType. For example: ```bash reflex deploy --project f88b1574-f101-####-####-5f########## --vmtype c2m4 ``` This will deploy your app with the `c2m4` VMType, giving your app 2 CPU cores and 4 GB of RAM. # Regions Source: http://localhost:3000/docs/hosting/regions.md ```python exec import reflex as rx REGIONS_DICT = { "ams": "Amsterdam, Netherlands", "arn": "Stockholm, Sweden", "bom": "Mumbai, India", "cdg": "Paris, France", "dfw": "Dallas, Texas (US)", "ewr": "Secaucus, NJ (US)", "fra": "Frankfurt, Germany", "gru": "Sao Paulo, Brazil", "iad": "Ashburn, Virginia (US)", "jnb": "Johannesburg, South Africa", "lax": "Los Angeles, California (US)", "lhr": "London, United Kingdom", "nrt": "Tokyo, Japan", "ord": "Chicago, Illinois (US)", "sjc": "San Jose, California (US)", "sin": "Singapore, Singapore", "syd": "Sydney, Australia", "yyz": "Toronto, Canada", } COUNTRIES_CODES = { "ams": "NL", "arn": "SE", "bom": "IN", "cdg": "FR", "dfw": "US", "ewr": "US", "fra": "DE", "gru": "BR", "iad": "US", "jnb": "ZA", "lax": "US", "lhr": "GB", "nrt": "JP", "ord": "US", "sjc": "US", "sin": "SG", "syd": "AU", "yyz": "CA", } ``` ## Regions To scale your app you can choose different regions. Regions are different locations around the world where your app can be deployed. To scale your app to multiple regions in the Cloud UI, click on the `Settings` tab in the Cloud UI on the app page, and then click on the `Regions` tab as shown below. Clicking on the `Add new region` button will allow you to scale your app to multiple regions. ```python eval rx.image( src="https://web.reflex-assets.dev/other/scaling_regions.webp", padding_bottom="20px", ) ``` The table below show all the regions that can be deployed in. ```python eval rx.el.table( rx.el.thead( rx.el.tr( rx.el.th( rx.el.div( "Region", ), class_name="px-6 py-3 text-left text-sm font-semibold text-secondary-12 text-nowrap", ), rx.el.th( rx.el.div( "Country", ), class_name="px-6 py-3 text-left text-sm font-semibold text-secondary-12 text-nowrap", ), ), class_name="bg-slate-2", ), rx.el.tbody( *[ rx.el.tr( rx.el.td( rx.el.div( region, class_name="h-5 rounded-md border justify-start items-center inline-flex bg-slate-1 text-xs font-medium shrink-0 px-1.5 w-fit text-slate-12 border-slate-6", ), class_name="px-6 py-3", ), rx.el.td( rx.el.div( rx.image( src=f"https://build.reflex.dev/flags/{COUNTRIES_CODES[region]}.svg", class_name="rounded-[2px] mr-2 w-5 h-4", ), REGIONS_DICT[region], class_name="flex flex-row items-center gap-2", ), class_name="px-6 py-3 text-sm font-medium text-slate-9", ), class_name="even:bg-slate-2 odd:bg-slate-1 hover:bg-secondary-3", ) for region in REGIONS_DICT.keys() ], class_name="divide-y divide-slate-4", ), class_name="w-full table-fixed rounded-xl overflow-hidden divide-y divide-slate-4", ) ``` ### Selecting Regions to Deploy in the CLI Below is an example of how to deploy your app in several regions: ```bash reflex deploy --project f88b1574-f101-####-####-5f########## --region sjc --region iad ``` By default all apps are deloyed in `sjc` if no other regions are given. If you wish to deploy in another region or several regions you can pass the `--region` flag (`-r` also works) with the region code. Check out all the regions that we can deploy to below: ## Config File To create a `config.yml` file for your app run the command below: ```bash reflex cloud config ``` This will create a yaml file similar to the one below where you can edit the app configuration: ```yaml name: medo description: '' regions: sjc: 1 lhr: 2 vmtype: c1m1 hostname: null envfile: .env project: null packages: - procps ``` # Secrets (Environment Variables) Source: http://localhost:3000/docs/hosting/secrets-environment-vars.md ```python exec import reflex as rx ``` ## Adding Secrets through the CLI Below is an example of how to use an environment variable file. You can pass the `--envfile` flag with the path to the env file. For example: ```bash reflex deploy --project f88b1574-f101-####-####-5f########## --envfile .env ``` In this example the path to the file is `.env`. If you prefer to pass the environment variables manually below is deployment command example: ```bash reflex deploy --project f88b1574-f101-####-####-5f########## --env OPENAI_API_KEY=sk-proj-vD4i9t6U############################ ``` They are passed after the `--env` flag as key value pairs. To pass multiple environment variables, you can repeat the `--env` tag. i.e. `reflex deploy --project f88b1574-f101-####-####-5f########## --env KEY1=VALUE1 --env KEY2=VALUE`. The `--envfile` flag will override any envs set manually. ```md alert info # More information on Environment Variables Environment variables are encrypted and safely stored. We recommend that backend API keys or secrets are entered as `envs`. Make sure to enter the `envs` without any quotation marks. We do not show the values of them in any CLI commands, only their names (or keys). You access the values of `envs` by referencing `os.environ` with their names as keys in your app's backend. For example, if you set an env `ASYNC_DB_URL`, you are able to access it by `os.environ["ASYNC_DB_URL"]`. Some Python libraries automatically look for certain environment variables. For example, `OPENAI_API_KEY` for the `openai` python client. The `boto3` client credentials can be configured by setting `AWS_ACCESS_KEY_ID`,`AWS_SECRET_ACCESS_KEY`. This information is typically available in the documentation of the Python packages you use. ``` ## Adding Secrets through the Cloud UI To find the secrets tab, click on the `Settings` tab in the Cloud UI on the app page. ```python eval rx.image(src="https://web.reflex-assets.dev/other/environment_variables.webp") ``` Then click on the `Secrets` tab as shown below. ```python eval rx.image(src="https://web.reflex-assets.dev/other/environment_variables_2.webp") ``` From here you can add or edit your environment variables. You will need to restart your app for these changes to take effect. This functionality in the UI can be disabled by an admin of the project. # Self Hosting Source: http://localhost:3000/docs/hosting/self-hosting.md ```python exec import reflex as rx ``` We recommend using `reflex deploy`, but if this does not fit your use case then you can also host your apps yourself. Clone your code to a server and install the [requirements](/docs/getting-started/installation/). ## API URL Edit your `rxconfig.py` file and set `api_url` to the publicly accessible IP address or hostname of your server, with the port `:8000` at the end. Setting this correctly is essential for the frontend to interact with the backend state. For example if your server is at `app.example.com`, your config would look like this: ```python config = rx.Config( app_name="your_app_name", api_url="http://app.example.com:8000", ) ``` It is also possible to set the environment variable `API_URL` at run time or export time to retain the default for local development. ## Proxying to a Subpath If you want to serve the backend behind a reverse proxy at a subpath (e.g. nginx routing `/api/*` to Reflex), set `backend_path` on the config instead of baking the prefix into `api_url`. Every backend endpoint (event websocket, `/ping`, `/_upload`, `/_health`, `/_all_routes`) is mounted under that prefix, and the frontend baked into the export automatically calls the backend at the prefixed URLs — no request rewriting in the proxy is required. ```python config = rx.Config( app_name="your_app_name", api_url="http://app.example.com:8000", backend_path="/api", ) ``` `frontend_path` plays the analogous role for the frontend and the two are independent. Note: changing `backend_path` (or `frontend_path`) requires a full restart of `reflex run` — routes and mount points are registered at startup, so hot reload alone will not move them. ## Production Mode Then run your app in production mode: ```bash reflex run --env prod ``` Production mode creates an optimized build of your app. By default, the static frontend of the app (HTML, Javascript, CSS) will be exposed on port `3000` and the backend (event handlers) will be listening on port `8000`. ```md alert warning # Reverse Proxy and Websockets Because the backend uses websockets, some reverse proxy servers, like [nginx](https://nginx.org/en/docs/http/websocket.html) or [apache](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#protoupgrade), must be configured to pass the `Upgrade` header to allow backend connectivity. ``` ## Exporting a Static Build Exporting a static build of the frontend allows the app to be served using a static hosting provider, like Netlify or Github Pages. Be sure `api_url` is set to an accessible backend URL when the frontend is exported. ```bash API_URL=http://app.example.com:8000 reflex export ``` This will create a `frontend.zip` file with your app's minified HTML, Javascript, and CSS build that can be uploaded to your static hosting service. It also creates a `backend.zip` file with your app's backend python code to upload to your server and run. You can export only the frontend or backend by passing in the `--frontend-only` or `--backend-only` flags. It is also possible to export the components without zipping. To do this, use the `--no-zip` parameter. This provides the frontend in the `.web/build/client/` directory and the backend can be found in the root directory of the project. ## Reflex Container Service Another option is to run your Reflex service in a container. For this purpose, a `Dockerfile` and additional documentation is available in the Reflex project in the directory `docker-example`. For the build of the container image it is necessary to edit the `rxconfig.py` and the add the `requirements.txt` to your project folder. The following changes are necessary in `rxconfig.py`: ```python config = rx.Config( app_name="app", api_url="http://app.example.com:8000", ) ``` Notice that the `api_url` should be set to the externally accessible hostname or IP, as the client browser must be able to connect to it directly to establish interactivity. You can find the `requirements.txt` in the `docker-example` folder of the project too. The project structure should looks like this: ```bash hello ├── .web ├── assets ├── hello │ ├── __init__.py │ └── hello.py ├── rxconfig.py ├── Dockerfile └── requirements.txt ``` After all changes have been made, the container image can now be created as follows. ```bash docker build -t reflex-project:latest . ``` Finally, you can start your Reflex container service as follows. ```bash docker run -d -p 3000:3000 -p 8000:8000 --name app reflex-project:latest ``` # Tokens Source: http://localhost:3000/docs/hosting/tokens.md ```python exec import reflex as rx ``` A token gives someone else all the permissions you have as a User or Admin. They can run any Reflex Cloud command from the CLI as if they were you, using the `--token` flag. A common use case is for GitHub Actions (you store this token in your secrets). To access or create tokens, first click the avatar in the top-right corner to open the drop-down menu, then click `Account Settings`. ```python eval rx.image( src="https://web.reflex-assets.dev/other/hosting_tokens_1.webp", alt="Adding tokens to Reflex Cloud", padding="1em 0em", ) ``` Clicking `Account Settings` will redirect you to both the `Settings` and `Tokens` dashboards. Click the `Tokens` tab at the top to access your tokens or create new ones. ```python eval rx.image( src="https://web.reflex-assets.dev/other/hosting_tokens_2.webp", alt="Adding tokens to Reflex Cloud", padding="1em 0em", ) ``` # Avatar Source: http://localhost:3000/docs/library/data-display/avatar.md --- components: - rx.avatar Avatar: | lambda **props: rx.hstack(rx.avatar(src="https://web.reflex-assets.dev/other/logo.jpg", **props), rx.avatar(fallback="RX", **props), spacing="3") --- ```python exec import reflex as rx ``` The Avatar component is used to represent a user, and display their profile pictures or fallback texts such as initials. ## Basic Example To create an avatar component with an image, pass the image URL as the `src` prop. ```python demo rx.avatar(src="https://web.reflex-assets.dev/other/logo.jpg") ``` To display a text such as initials, set the `fallback` prop without passing the `src` prop. ```python demo rx.avatar(fallback="RX") ``` ## Styling ### Size The `size` prop controls the size and spacing of the avatar. The acceptable size is from `"1"` to `"9"`, with `"3"` being the default. ```python demo rx.flex( rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", size="1" ), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", size="2" ), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", size="3" ), rx.avatar(src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX"), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", size="4" ), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", size="5" ), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", size="6" ), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", size="7" ), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", size="8" ), spacing="1", ) ``` ### Variant The `variant` prop controls the visual style of the avatar fallback text. The variant can be `"solid"` or `"soft"`. The default is `"soft"`. ```python demo rx.flex( rx.avatar(fallback="RX", variant="solid"), rx.avatar(fallback="RX", variant="soft"), rx.avatar(fallback="RX"), spacing="2", ) ``` ### Color Scheme The `color_scheme` prop sets a specific color to the fallback text, ignoring the global theme. ```python demo rx.flex( rx.avatar(fallback="RX", color_scheme="indigo"), rx.avatar(fallback="RX", color_scheme="cyan"), rx.avatar(fallback="RX", color_scheme="orange"), rx.avatar(fallback="RX", color_scheme="crimson"), spacing="2", ) ``` ### High Contrast The `high_contrast` prop increases color contrast of the fallback text with the background. ```python demo rx.grid( rx.avatar(fallback="RX", variant="solid"), rx.avatar(fallback="RX", variant="solid", high_contrast=True), rx.avatar(fallback="RX", variant="soft"), rx.avatar(fallback="RX", variant="soft", high_contrast=True), rows="2", spacing="2", flow="column", ) ``` ### Radius The `radius` prop sets specific radius value, ignoring the global theme. It can take values `"none" | "small" | "medium" | "large" | "full"`. ```python demo rx.grid( rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", radius="none" ), rx.avatar(fallback="RX", radius="none"), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", radius="small", ), rx.avatar(fallback="RX", radius="small"), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", radius="medium", ), rx.avatar(fallback="RX", radius="medium"), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", radius="large", ), rx.avatar(fallback="RX", radius="large"), rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RX", radius="full" ), rx.avatar(fallback="RX", radius="full"), rows="2", spacing="2", flow="column", ) ``` ### Fallback The `fallback` prop indicates the rendered text when the `src` cannot be loaded. ```python demo rx.flex( rx.avatar(fallback="RX"), rx.avatar(fallback="PC"), spacing="2", ) ``` ## Final Example As part of a user profile page, the Avatar component is used to display the user's profile picture, with the fallback text showing the user's initials. Text components displays the user's full name and username handle and a Button component shows the edit profile button. ```python demo rx.flex( rx.avatar( src="https://web.reflex-assets.dev/other/logo.jpg", fallback="RU", size="9" ), rx.text("Reflex User", weight="bold", size="4"), rx.text("@reflexuser", color_scheme="gray"), rx.button("Edit Profile", color_scheme="indigo", variant="solid"), direction="column", spacing="1", ) ``` ## API Reference ### rx.avatar An image element with a fallback for representing the user. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `variant` | Literal["solid", "soft"] | - | The variant of the avatar. | | `size` | Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"], Breakpoints[str, Literal["1", "2", "3", "4", "5", "6", "7", "8", "9"]] | - | The size of the avatar: "1" - "9". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Color theme of the avatar. | | `high_contrast` | bool | - | Whether to render the avatar with higher contrast color against background. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | Override theme radius for avatar: "none", "small", "medium", "large", "full". | | `src` | str | - | The src of the avatar image. | | `fallback` | str | - | The rendered fallback text. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Badge Source: http://localhost:3000/docs/library/data-display/badge.md --- components: - rx.badge Badge: | lambda **props: rx.badge("Basic Badge", **props) --- ```python exec import reflex as rx ``` Badges are used to highlight an item's status for quick recognition. ## Basic Example To create a badge component with only text inside, pass the text as an argument. ```python demo rx.badge("New") ``` ## Styling ### Size The `size` prop controls the size and padding of a badge. It can take values of `"1" | "2"`, with default being `"1"`. ```python demo rx.flex( rx.badge("New"), rx.badge("New", size="1"), rx.badge("New", size="2"), align="center", spacing="2", ) ``` ### Variant The `variant` prop controls the visual style of the badge. The supported variant types are `"solid" | "soft" | "surface" | "outline"`. The variant default is `"soft"`. ```python demo rx.flex( rx.badge("New", variant="solid"), rx.badge("New", variant="soft"), rx.badge("New"), rx.badge("New", variant="surface"), rx.badge("New", variant="outline"), spacing="2", ) ``` ### Color Scheme The `color_scheme` prop sets a specific color, ignoring the global theme. ```python demo rx.flex( rx.badge("New", color_scheme="indigo"), rx.badge("New", color_scheme="cyan"), rx.badge("New", color_scheme="orange"), rx.badge("New", color_scheme="crimson"), spacing="2", ) ``` ### High Contrast The `high_contrast` prop increases color contrast of the fallback text with the background. ```python demo rx.flex( rx.flex( rx.badge("New", variant="solid"), rx.badge("New", variant="soft"), rx.badge("New", variant="surface"), rx.badge("New", variant="outline"), spacing="2", ), rx.flex( rx.badge("New", variant="solid", high_contrast=True), rx.badge("New", variant="soft", high_contrast=True), rx.badge("New", variant="surface", high_contrast=True), rx.badge("New", variant="outline", high_contrast=True), spacing="2", ), direction="column", spacing="2", ) ``` ### Radius The `radius` prop sets specific radius value, ignoring the global theme. It can take values `"none" | "small" | "medium" | "large" | "full"`. ```python demo rx.flex( rx.badge("New", radius="none"), rx.badge("New", radius="small"), rx.badge("New", radius="medium"), rx.badge("New", radius="large"), rx.badge("New", radius="full"), spacing="3", ) ``` ## Final Example A badge may contain more complex elements within it. This example uses a `flex` component to align an icon and the text correctly, using the `gap` prop to ensure a comfortable spacing between the two. ```python demo rx.badge( rx.flex( rx.icon(tag="arrow_up"), rx.text("8.8%"), spacing="1", ), color_scheme="grass", ) ``` ## API Reference ### rx.badge A stylized badge element. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `variant` | Literal["solid", "soft", "surface", "outline"] | - | The variant of the badge. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the badge. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Color theme of the badge. | | `high_contrast` | bool | - | Whether to render the badge with higher contrast color against background. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | Override theme radius for badge: "none", "small", "medium", "large", "full". | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Callout Source: http://localhost:3000/docs/library/data-display/callout.md --- components: - rx.callout - rx.callout.root - rx.callout.icon - rx.callout.text Callout: | lambda **props: rx.callout("Basic Callout", icon="search", **props) CalloutRoot: | lambda **props: rx.callout.root( rx.callout.icon(rx.icon(tag="info")), rx.callout.text("You will need admin privileges to install and access this application."), **props ) --- ```python exec import reflex as rx ``` A `callout` is a short message to attract user's attention. ```python demo rx.callout( "You will need admin privileges to install and access this application.", icon="info", ) ``` The `icon` prop allows an icon to be passed to the `callout` component. See the [**icon** component for all icons that are available.](/docs/library/data-display/icon) ## As alert ```python demo rx.callout( "Access denied. Please contact the network administrator to view this page.", icon="triangle_alert", color_scheme="red", role="alert", ) ``` ## Style ### Size Use the `size` prop to control the size. ```python demo rx.flex( rx.callout( "You will need admin privileges to install and access this application.", icon="info", size="3", ), rx.callout( "You will need admin privileges to install and access this application.", icon="info", size="2", ), rx.callout( "You will need admin privileges to install and access this application.", icon="info", size="1", ), direction="column", spacing="3", align="start", ) ``` ### Variant Use the `variant` prop to control the visual style. It is set to `soft` by default. ```python demo rx.flex( rx.callout( "You will need admin privileges to install and access this application.", icon="info", variant="soft", ), rx.callout( "You will need admin privileges to install and access this application.", icon="info", variant="surface", ), rx.callout( "You will need admin privileges to install and access this application.", icon="info", variant="outline", ), direction="column", spacing="3", ) ``` ### Color Use the `color_scheme` prop to assign a specific color, ignoring the global theme. ```python demo rx.flex( rx.callout( "You will need admin privileges to install and access this application.", icon="info", color_scheme="blue", ), rx.callout( "You will need admin privileges to install and access this application.", icon="info", color_scheme="green", ), rx.callout( "You will need admin privileges to install and access this application.", icon="info", color_scheme="red", ), direction="column", spacing="3", ) ``` ### High Contrast Use the `high_contrast` prop to add additional contrast. ```python demo rx.flex( rx.callout( "You will need admin privileges to install and access this application.", icon="info", ), rx.callout( "You will need admin privileges to install and access this application.", icon="info", high_contrast=True, ), direction="column", spacing="3", ) ``` ## API Reference ### rx.callout A short message to attract user's attention. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `as_child` | bool | - | Change the default rendered element for the one passed as a child, merging their props and behavior. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | Size "1" - "3". | | `variant` | Literal["soft", "surface", "outline"] | - | Variant of button: "soft", "surface", "outline". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for button. | | `high_contrast` | bool | - | Whether to render the button with higher contrast color against background. | | `text` | str | - | The text of the callout. | | `icon` | str | - | The icon of the callout. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.callout.root Groups Icon and Text parts of a Callout. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `as_child` | bool | - | Change the default rendered element for the one passed as a child, merging their props and behavior. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | Size "1" - "3". | | `variant` | Literal["soft", "surface", "outline"] | - | Variant of button: "soft", "surface", "outline". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for button. | | `high_contrast` | bool | - | Whether to render the button with higher contrast color against background. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.callout.icon Provides width and height for the icon associated with the callout. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.callout.text Renders the callout text. This component is based on the p element. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Code Block Source: http://localhost:3000/docs/library/data-display/code-block.md --- components: - rx.code_block --- ```python exec import reflex as rx ``` The Code Block component can be used to display code easily within a website. Put in a multiline string with the correct spacing and specify and language to show the desired code. ```python demo rx.code_block( """def fib(n): if n <= 1: return n else: return(fib(n-1) + fib(n-2))""", language="python", show_line_numbers=True, ) ``` ## Themes The `theme` prop must be set to a `Theme` value accessed from the `rx.code_block.themes` namespace; strings are not accepted. By default, the code block uses `one_light` in light mode and `one_dark` in dark mode. ```python demo rx.code_block( """print("Hello, world!")""", language="python", theme=rx.code_block.themes.dracula, ) ``` To pick a theme that responds to the global color mode, pass `rx.color_mode_cond` with the desired light and dark variants: ```python demo rx.code_block( """print("Hello, world!")""", language="python", theme=rx.color_mode_cond( light=rx.code_block.themes.one_light, dark=rx.code_block.themes.one_dark, ), ) ``` ## API Reference ### rx.code_block A code block. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `theme` | Theme | - | The theme to use, accessed via rx.code_block.themes (e.g. rx.code_block.themes.one_dark). | | `language` | Literal["abap", "abnf", "actionscript", "ada", "agda", "al", "antlr4", "apacheconf", "apex", "apl", "applescript", "aql", "arduino", "arff", "asciidoc", "asm6502", "asmatmel", "aspnet", "autohotkey", "autoit", "avisynth", "avro-idl", "bash", "basic", "batch", "bbcode", "bicep", "birb", "bison", "bnf", "brainfuck", "brightscript", "bro", "bsl", "c", "cfscript", "chaiscript", "cil", "clike", "clojure", "cmake", "cobol", "coffeescript", "concurnas", "coq", "core", "cpp", "crystal", "csharp", "cshtml", "csp", "css", "css-extras", "csv", "cypher", "d", "dart", "dataweave", "dax", "dhall", "diff", "django", "dns-zone-file", "docker", "dot", "ebnf", "editorconfig", "eiffel", "ejs", "elixir", "elm", "erb", "erlang", "etlua", "excel-formula", "factor", "false", "firestore-security-rules", "flow", "fortran", "fsharp", "ftl", "gap", "gcode", "gdscript", "gedcom", "gherkin", "git", "glsl", "gml", "gn", "go", "go-module", "graphql", "groovy", "haml", "handlebars", "haskell", "haxe", "hcl", "hlsl", "hoon", "hpkp", "hsts", "http", "ichigojam", "icon", "icu-message-format", "idris", "iecst", "ignore", "index", "inform7", "ini", "io", "j", "java", "javadoc", "javadoclike", "javascript", "javastacktrace", "jexl", "jolie", "jq", "js-extras", "js-templates", "jsdoc", "json", "json5", "jsonp", "jsstacktrace", "jsx", "julia", "keepalived", "keyman", "kotlin", "kumir", "kusto", "latex", "latte", "less", "lilypond", "liquid", "lisp", "livescript", "llvm", "log", "lolcode", "lua", "magma", "makefile", "markdown", "markup", "markup-templating", "matlab", "maxscript", "mel", "mermaid", "mizar", "mongodb", "monkey", "moonscript", "n1ql", "n4js", "nand2tetris-hdl", "naniscript", "nasm", "neon", "nevod", "nginx", "nim", "nix", "nsis", "objectivec", "ocaml", "opencl", "openqasm", "oz", "parigp", "parser", "pascal", "pascaligo", "pcaxis", "peoplecode", "perl", "php", "php-extras", "phpdoc", "plsql", "powerquery", "powershell", "processing", "prolog", "promql", "properties", "protobuf", "psl", "pug", "puppet", "pure", "purebasic", "purescript", "python", "q", "qml", "qore", "qsharp", "r", "racket", "reason", "regex", "rego", "renpy", "rest", "rip", "roboconf", "robotframework", "ruby", "rust", "sas", "sass", "scala", "scheme", "scss", "shell-session", "smali", "smalltalk", "smarty", "sml", "solidity", "solution-file", "soy", "sparql", "splunk-spl", "sqf", "sql", "squirrel", "stan", "stylus", "swift", "systemd", "t4-cs", "t4-templating", "t4-vb", "tap", "tcl", "textile", "toml", "tremor", "tsx", "tt2", "turtle", "twig", "typescript", "typoscript", "unrealscript", "uorazor", "uri", "v", "vala", "vbnet", "velocity", "verilog", "vhdl", "vim", "visual-basic", "warpscript", "wasm", "web-idl", "wiki", "wolfram", "wren", "xeora", "xml-doc", "xojo", "xquery", "yaml", "yang", "zig"] | - | The language to use. | | `code` | str | - | The code to display. | | `show_line_numbers` | bool | - | If this is enabled line numbers will be shown next to the code block. | | `starting_line_number` | int | - | The starting line number to use. | | `wrap_long_lines` | bool | - | Whether to wrap long lines. | | `code_tag_props` | dict[str, str, dict[str, str]] | - | Props passed down to the code tag. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Data List Source: http://localhost:3000/docs/library/data-display/data-list.md --- components: - rx.data_list.root - rx.data_list.item - rx.data_list.label - rx.data_list.value DataListRoot: | lambda **props: rx.data_list.root( rx.foreach( [["Status", "Authorized"], ["ID", "U-474747"], ["Name", "Developer Success"], ["Email", "foo@reflex.dev"]], lambda item: rx.data_list.item(rx.data_list.label(item[0]), rx.data_list.value(item[1])), ), **props, ) DataListItem: | lambda **props: rx.data_list.root( rx.data_list.item( rx.data_list.label("Status"), rx.data_list.value(rx.badge("Authorized", variant="soft", radius="full", size="2")), **props, ), rx.data_list.item( rx.data_list.label("Name"), rx.data_list.value(rx.heading("Developer Success", size="4")), **props, ), rx.data_list.item( rx.data_list.label("Email"), rx.data_list.value(rx.link("foo@reflex.dev", href="mailto:foo@reflex.dev")), **props, ), ) DataListLabel: | lambda **props: rx.data_list.root( rx.foreach( [["Status", "Authorized"], ["ID", "U-474747"], ["Name", "Developer Success"], ["Email", "foo@reflex.dev"]], lambda item: rx.data_list.item(rx.data_list.label(item[0], **props), rx.data_list.value(item[1])), ), ) DataListValue: | lambda **props: rx.data_list.root( rx.foreach( [["Status", "Authorized"], ["ID", "U-474747"], ["Name", "Developer Success"], ["Email", "foo@reflex.dev"]], lambda item: rx.data_list.item(rx.data_list.label(item[0]), rx.data_list.value(item[1], **props)), ), ) --- ```python exec import reflex as rx ``` The `DataList` component displays key-value pairs and is particularly helpful for showing metadata. A `DataList` needs to be initialized using `rx.data_list.root()` and currently takes in data list items: `rx.data_list.item` ```python demo ( rx.card( rx.data_list.root( rx.data_list.item( rx.data_list.label("Status"), rx.data_list.value( rx.badge( "Authorized", variant="soft", radius="full", ) ), align="center", ), rx.data_list.item( rx.data_list.label("ID"), rx.data_list.value(rx.code("U-474747")), ), rx.data_list.item( rx.data_list.label("Name"), rx.data_list.value("Developer Success"), align="center", ), rx.data_list.item( rx.data_list.label("Email"), rx.data_list.value( rx.link( "success@reflex.dev", href="mailto:success@reflex.dev", ), ), ), rx.data_list.item( rx.data_list.label("Company"), rx.data_list.value( rx.link( "Reflex", href="https://reflex.dev", ), ), ), ), ), ) ``` ## API Reference ### rx.data_list.root Root element for a DataList component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `orientation` | Literal["horizontal", "vertical"], Breakpoints[str, Literal["horizontal", "vertical"]] | - | The orientation of the data list item: "horizontal", "vertical". | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the data list item: "1", "2", "3". | | `trim` | Literal["normal", "start", "end", "both"], Breakpoints[str, Literal["normal", "start", "end", "both"]] | - | Trims the leading whitespace from the start or end of the text. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.data_list.item An item in the DataList component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `align` | Literal["start", "center", "end", "baseline", "stretch"], Breakpoints[str, Literal["start", "center", "end", "baseline", "stretch"]] | - | The alignment of the data list item within its container. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.data_list.label A label in the DataList component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, Breakpoints[str, str] | - | The width of the component. | | `min_width` | str, Breakpoints[str, str] | - | The minimum width of the component. | | `max_width` | str, Breakpoints[str, str] | - | The maximum width of the component. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color scheme for the DataList component. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.data_list.value A value in the DataList component. #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Icon Source: http://localhost:3000/docs/library/data-display/icon.md --- components: - rx.lucide.Icon --- ```python exec import reflex as rx from reflex_components_lucide.icon import LUCIDE_ICON_LIST from reflex.experimental.client_state import ClientStateVar icon_search_cs = ClientStateVar.create("icon_search", default="") @rx.memo def lucide_icons(): return rx.box( rx.box( rx.box( rx.icon( tag="search", size=20, class_name="shrink-0 !text-slate-11", ), class_name="absolute left-2 top-1/2 transform -translate-y-1/2 z-[1] shrink-0 flex items-center justify-center pb-2", ), rx.el.input( placeholder="Search icons...", on_change=icon_search_cs.set_value, class_name="relative box-border border-slate-4 focus:border-violet-9 focus:border-1 bg-slate-2 p-[0.5rem_0.75rem] border rounded-xl font-base text-slate-11 placeholder:text-slate-9 outline-none focus:outline-none w-full mb-2 pl-10", ), class_name="relative flex items-center", ), rx.el.div( rx.box( rx.foreach( LUCIDE_ICON_LIST, lambda icon: rx.cond( icon.startswith(icon_search_cs.value), rx.tooltip( rx.box( rx.icon(tag=icon), class_name="flex items-center justify-center rounded-md hover:bg-slate-3 transition-bg p-2 cursor-pointer", on_click=[ rx.set_clipboard(icon), rx.toast.success(f"Copied {icon} to clipboard"), ], key=icon, ), content=icon, ), None, ), ), class_name="flex flex-wrap justify-start gap-4 mb-4", ), class_name="overflow-y-auto max-h-[500px]", ), class_name="flex flex-col gap-4", ) ``` The Icon component is used to display an icon from a library of icons. This implementation is based on the [Lucide Icons](https://lucide.dev/icons) where you can find a list of all available icons. ## Icons List ```python eval lucide_icons() ``` ## Basic Example To display an icon, specify the `tag` prop from the list of available icons. Passing the tag as the first children is also supported and will be assigned to the `tag` prop. The `tag` is expected to be in `snake_case` format, but `kebab-case` is also supported to allow copy-paste from [https://lucide.dev/icons](https://lucide.dev/icons). ```python demo rx.flex( rx.icon("calendar"), rx.icon(tag="calendar"), gap="2", ) ``` ## Dynamic Icons There are two ways to use dynamic icons in Reflex: ### Using rx.match If you have a specific subset of icons you want to use dynamically, you can define an `rx.match` with them: ```python def dynamic_icon_with_match(icon_name): return rx.match( icon_name, ("plus", rx.icon("plus")), ("minus", rx.icon("minus")), ("equal", rx.icon("equal")), ) ``` ```python exec def dynamic_icon_with_match(icon_name): return rx.match( icon_name, ("plus", rx.icon("plus")), ("minus", rx.icon("minus")), ("equal", rx.icon("equal")), ) ``` ### Using Dynamic Icon Tags Reflex also supports using dynamic values directly as the `tag` prop in `rx.icon()`. This allows you to use any icon from the Lucide library dynamically at runtime. ```python exec class DynamicIconState(rx.State): current_icon: str = "heart" def change_icon(self): icons = ["heart", "star", "bell", "calendar", "settings"] import random self.current_icon = random.choice(icons) ``` ```python demo rx.vstack( rx.heading("Dynamic Icon Example"), rx.icon(DynamicIconState.current_icon, size=30, color="red"), rx.button("Change Icon", on_click=DynamicIconState.change_icon), spacing="4", align="center", ) ``` Under the hood, when a dynamic value is passed as the `tag` prop to `rx.icon()`, Reflex automatically uses a special `DynamicIcon` component that can load icons at runtime. ```md alert When using dynamic icons, make sure the icon names are valid. Invalid icon names will cause runtime errors. ``` ## Styling Icon from Lucide can be customized with the following props `stroke_width`, `size` and `color`. ### Stroke Width ```python demo rx.flex( rx.icon("moon", stroke_width=1), rx.icon("moon", stroke_width=1.5), rx.icon("moon", stroke_width=2), rx.icon("moon", stroke_width=2.5), gap="2", ) ``` ### Size ```python demo rx.flex( rx.icon("zoom_in", size=15), rx.icon("zoom_in", size=20), rx.icon("zoom_in", size=25), rx.icon("zoom_in", size=30), align="center", gap="2", ) ``` ### Color Here is an example using basic colors in icons. ```python demo rx.flex( rx.icon("zoom_in", size=18, color="indigo"), rx.icon("zoom_in", size=18, color="cyan"), rx.icon("zoom_in", size=18, color="orange"), rx.icon("zoom_in", size=18, color="crimson"), gap="2", ) ``` A radix color with a scale may also be specified using `rx.color()` as seen below. ```python demo rx.flex( rx.icon("zoom_in", size=18, color=rx.color("purple", 1)), rx.icon("zoom_in", size=18, color=rx.color("purple", 2)), rx.icon("zoom_in", size=18, color=rx.color("purple", 3)), rx.icon("zoom_in", size=18, color=rx.color("purple", 4)), rx.icon("zoom_in", size=18, color=rx.color("purple", 5)), rx.icon("zoom_in", size=18, color=rx.color("purple", 6)), rx.icon("zoom_in", size=18, color=rx.color("purple", 7)), rx.icon("zoom_in", size=18, color=rx.color("purple", 8)), rx.icon("zoom_in", size=18, color=rx.color("purple", 9)), rx.icon("zoom_in", size=18, color=rx.color("purple", 10)), rx.icon("zoom_in", size=18, color=rx.color("purple", 11)), rx.icon("zoom_in", size=18, color=rx.color("purple", 12)), gap="2", ) ``` Here is another example using the `accent` color with scales. The `accent` is the most dominant color in your theme. ```python demo rx.flex( rx.icon("zoom_in", size=18, color=rx.color("accent", 1)), rx.icon("zoom_in", size=18, color=rx.color("accent", 2)), rx.icon("zoom_in", size=18, color=rx.color("accent", 3)), rx.icon("zoom_in", size=18, color=rx.color("accent", 4)), rx.icon("zoom_in", size=18, color=rx.color("accent", 5)), rx.icon("zoom_in", size=18, color=rx.color("accent", 6)), rx.icon("zoom_in", size=18, color=rx.color("accent", 7)), rx.icon("zoom_in", size=18, color=rx.color("accent", 8)), rx.icon("zoom_in", size=18, color=rx.color("accent", 9)), rx.icon("zoom_in", size=18, color=rx.color("accent", 10)), rx.icon("zoom_in", size=18, color=rx.color("accent", 11)), rx.icon("zoom_in", size=18, color=rx.color("accent", 12)), gap="2", ) ``` ## Final Example Icons can be used as child components of many other components. For example, adding a magnifying glass icon to a search bar. ```python demo rx.badge( rx.flex( rx.icon("search", size=18), rx.text("Search documentation...", size="3", weight="medium"), direction="row", gap="1", align="center", ), size="2", radius="full", color_scheme="gray", ) ``` ## API Reference ### rx.lucide.Icon An Icon component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | int | - | The size of the icon in pixels. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # List Source: http://localhost:3000/docs/library/data-display/list.md --- components: - rx.list.item - rx.list.ordered - rx.list.unordered --- ```python exec import reflex as rx ``` A `list` is a component that is used to display a list of items, stacked vertically by default. A `list` can be either `ordered` or `unordered`. It is based on the `flex` component and therefore inherits all of its props. `list.unordered` has bullet points to display the list items. ```python demo rx.list.unordered( rx.list.item("Example 1"), rx.list.item("Example 2"), rx.list.item("Example 3"), ) ``` `list.ordered` has numbers to display the list items. ```python demo rx.list.ordered( rx.list.item("Example 1"), rx.list.item("Example 2"), rx.list.item("Example 3"), ) ``` `list.unordered()` and `list.ordered()` can have no bullet points or numbers by setting the `list_style_type` prop to `none`. This is effectively the same as using the `list()` component. ```python demo rx.hstack( rx.list( rx.list.item("Example 1"), rx.list.item("Example 2"), rx.list.item("Example 3"), ), rx.list.unordered( rx.list.item("Example 1"), rx.list.item("Example 2"), rx.list.item("Example 3"), list_style_type="none", ), ) ``` Lists can also be used with icons. ```python demo rx.list( rx.list.item( rx.icon("circle_check_big", color="green"), " Allowed", ), rx.list.item( rx.icon("octagon_x", color="red"), " Not", ), rx.list.item(rx.icon("settings", color="grey"), " Settings"), list_style_type="none", ) ``` ## API Reference ### rx.list.item Display an item of an ordered or unordered list. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.list.ordered Display an ordered list. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `reversed` | bool | - | Reverses the order of the list. | | `start` | int | - | Specifies the start value of the first list item in an ordered list. | | `type` | Literal["1", "a", "A", "i", "I"] | - | Specifies the kind of marker to use in the list (letters or numbers). | | `list_style_type` | Literal["none", "disc", "circle", "square"], Literal["none", "decimal", "decimal-leading-zero", "lower-roman", "upper-roman", "lower-greek", "lower-latin", "upper-latin", "armenian", "georgian", "lower-alpha", "upper-alpha", "hiragana", "katakana"] | - | The style of the list. Default to "none". | | `items` | Iterable | - | A list of items to add to the list. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.list.unordered Display an unordered list. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `list_style_type` | Literal["none", "disc", "circle", "square"], Literal["none", "decimal", "decimal-leading-zero", "lower-roman", "upper-roman", "lower-greek", "lower-latin", "upper-latin", "armenian", "georgian", "lower-alpha", "upper-alpha", "hiragana", "katakana"] | - | The style of the list. Default to "none". | | `items` | Iterable | - | A list of items to add to the list. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Moment Source: http://localhost:3000/docs/library/data-display/moment.md --- components: - rx.moment --- Displaying date and relative time to now sometimes can be more complicated than necessary. To make it easy, Reflex is wrapping [react-moment](https://www.npmjs.com/package/react-moment) under `rx.moment`. ```python exec import reflex as rx from reflex.utils.serializers import serialize_datetime ``` ## Examples Using a date from a state var as a value, we will display it in a few different way using `rx.moment`. The `date_now` state var is initialized when the site was deployed. The button below can be used to update the var to the current datetime, which will be reflected in the subsequent examples. ```python demo exec from datetime import datetime, timezone class MomentState(rx.State): date_now: datetime = datetime.now(timezone.utc) @rx.event def update(self): self.date_now = datetime.now(timezone.utc) def moment_update_example(): return rx.button( "Update", rx.moment(MomentState.date_now), on_click=MomentState.update ) ``` ### Display the date as-is: ```python demo rx.moment(MomentState.date_now) ``` ### Humanized interval Sometimes we don't want to display just a raw date, but we want something more instinctive to read. That's when we can use `from_now` and `to_now`. ```python demo rx.moment(MomentState.date_now, from_now=True) ``` ```python demo rx.moment(MomentState.date_now, to_now=True) ``` You can also set a duration (in milliseconds) with `from_now_during` where the date will display as relative, then after that, it will be displayed as defined in `format`. ```python demo rx.moment( MomentState.date_now, from_now_during=100000 ) # after 100 seconds, date will display normally ``` ### Formatting dates ```python demo rx.moment(MomentState.date_now, format="YYYY-MM-DD") ``` ```python demo rx.moment(MomentState.date_now, format="HH:mm:ss") ``` ### Offset Date With the props `add` and `subtract`, you can pass an `rx.MomentDelta` object to modify the displayed date without affecting the stored date in your state. #### Add ```python demo rx.vstack( rx.moment( MomentState.date_now, add=rx.MomentDelta(years=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, add=rx.MomentDelta(quarters=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, add=rx.MomentDelta(months=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, add=rx.MomentDelta(weeks=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, add=rx.MomentDelta(days=2), format="YYYY-MM-DD - HH:mm:ss" ), rx.moment( MomentState.date_now, add=rx.MomentDelta(hours=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, add=rx.MomentDelta(minutes=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, add=rx.MomentDelta(seconds=2), format="YYYY-MM-DD - HH:mm:ss", ), ) ``` #### Subtract ```python demo rx.vstack( rx.moment( MomentState.date_now, subtract=rx.MomentDelta(years=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, subtract=rx.MomentDelta(quarters=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, subtract=rx.MomentDelta(months=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, subtract=rx.MomentDelta(weeks=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, subtract=rx.MomentDelta(days=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, subtract=rx.MomentDelta(hours=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, subtract=rx.MomentDelta(minutes=2), format="YYYY-MM-DD - HH:mm:ss", ), rx.moment( MomentState.date_now, subtract=rx.MomentDelta(seconds=2), format="YYYY-MM-DD - HH:mm:ss", ), ) ``` ### Timezones You can also set dates to display in a specific timezone: ```python demo rx.vstack( rx.moment(MomentState.date_now, tz="America/Los_Angeles"), rx.moment(MomentState.date_now, tz="Europe/Paris"), rx.moment(MomentState.date_now, tz="Asia/Tokyo"), ) ``` ### Client-side periodic update If a date is not passed to `rx.moment`, it will use the client's current time. If you want to update the date every second, you can use the `interval` prop. ```python demo rx.moment(interval=1000, format="HH:mm:ss") ``` Even better, you can actually link an event handler to the `on_change` prop that will be called every time the date is updated: ```python demo exec class MomentLiveState(rx.State): updating: bool = False @rx.event def on_update(self, date): return rx.toast(f"Date updated: {date}") @rx.event def set_updating(self, value: bool): self.updating = value def moment_live_example(): return rx.hstack( rx.moment( format="HH:mm:ss", interval=rx.cond(MomentLiveState.updating, 5000, 0), on_change=MomentLiveState.on_update, ), rx.switch( is_checked=MomentLiveState.updating, on_change=MomentLiveState.set_updating, ), ) ``` ## API Reference ### rx.moment The Moment component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `interval` | int | - | How often the date update (how often time update / 0 to disable). | | `format` | str | - | Formats the date according to the given format string. | | `trim` | bool | - | When formatting duration time, the largest-magnitude tokens are automatically trimmed when they have no value. | | `parse` | str | - | Use the parse attribute to tell moment how to parse the given date when non-standard. | | `add` | MomentDelta | - | Add a delta to the base date (keys are "years", "quarters", "months", "weeks", "days", "hours", "minutes", "seconds"). | | `subtract` | MomentDelta | - | Subtract a delta to the base date (keys are "years", "quarters", "months", "weeks", "days", "hours", "minutes", "seconds"). | | `from_now` | bool | - | Displays the date as the time from now, e.g. "5 minutes ago". | | `from_now_short` | bool | - | Displays the relative time in a short format using abbreviated units (e.g., "1h", "2d", "3mo", "1y" instead of "1 hour ago", "2 days ago", etc.). | | `from_now_during` | int | - | Setting fromNowDuring will display the relative time as with fromNow but just during its value in milliseconds, after that format will be used instead. | | `to_now` | bool | - | Similar to fromNow, but gives the opposite interval. | | `with_title` | bool | - | Adds a title attribute to the element with the complete date. | | `title_format` | str | - | How the title date is formatted when using the withTitle attribute. | | `diff` | str | - | Show the different between this date and the rendered child. | | `decimal` | bool | - | Display the diff as decimal. | | `unit` | str | - | Display the diff in given unit. | | `duration` | str | - | Shows the duration (elapsed time) between two dates. duration property should be behind date property time-wise. | | `date` | str, datetime, date, time, timedelta | - | The date to display (also work if passed as children). | | `duration_from_now` | bool | - | Shows the duration (elapsed time) between now and the provided datetime. | | `unix` | bool | - | Tells Moment to parse the given date value as a unix timestamp. | | `local` | bool | - | Outputs the result in local time. | | `tz` | str | - | Display the date in the given timezone. | | `locale` | str | - | The locale to use when rendering. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fires when the date changes. | # Progress Source: http://localhost:3000/docs/library/data-display/progress.md --- components: - rx.progress Progress: | lambda **props: rx.box(rx.progress(value=50, **props), width="20rem") --- Progress is used to display the progress status for a task that takes a long time or consists of several steps. ```python exec import reflex as rx ``` ## Basic Example `rx.progress` expects the `value` prop to set the progress value. `width` is default to 100%, the width of its parent component. ```python demo rx.vstack( rx.progress(value=0), rx.progress(value=50), rx.progress(value=100), width="50%", ) ``` For a dynamic progress, you can assign a state variable to the `value` prop instead of a constant value. ```python demo exec import asyncio class ProgressState(rx.State): value: int = 0 @rx.event(background=True) async def start_progress(self): async with self: self.value = 0 while self.value < 100: await asyncio.sleep(0.1) async with self: self.value += 1 def live_progress(): return rx.hstack( rx.progress(value=ProgressState.value), rx.button("Start", on_click=ProgressState.start_progress), width="50%", ) ``` ## API Reference ### rx.progress A progress bar component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | int | - | The value of the progress bar: 0 to max (default 100). | | `max` | int | - | The maximum progress value. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the progress bar: "1", "2", "3". | | `variant` | Literal["classic", "surface", "soft"] | - | The variant of the progress bar: "classic", "surface", "soft". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color theme of the progress bar. | | `high_contrast` | bool | - | Whether to render the progress bar with higher contrast color against background. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | Override theme radius for progress bar: "none", "small", "medium", "large", "full". | | `duration` | str | - | The duration of the progress bar animation. Once the duration times out, the progress bar will start an indeterminate animation. | | `fill_color` | str | - | The color of the progress bar fill animation. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Scroll Area Source: http://localhost:3000/docs/library/data-display/scroll-area.md --- components: - rx.scroll_area ScrollArea: | lambda **props: rx.scroll_area( rx.flex( rx.text( """Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense "legible" and "readable"are often used synonymously, typographically they are separate but related concepts.""", size="5", ), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as "the quality of being decipherable and recognisable". For instance, if a "b" and an "h", or a "3" and an "8", are difficult to distinguish at small sizes, this is a problem of legibility.""", size="5", ), direction="column", spacing="4", height="100px", width="50%", ), **props ) --- ```python exec import random import reflex as rx ``` Custom styled, cross-browser scrollable area using native functionality. ## Basic Example ```python demo rx.scroll_area( rx.flex( rx.text( """Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense “legible” and “readable” are often used synonymously, typographically they are separate but related concepts.""", ), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as “the quality of being decipherable and recognisable”. For instance, if a “b” and an “h”, or a “3” and an “8”, are difficult to distinguish at small sizes, this is a problem of legibility.""", ), rx.text( """Typographers are concerned with legibility insofar as it is their job to select the correct font to use. Brush Script is an example of a font containing many characters that might be difficult to distinguish. The selection of cases influences the legibility of typography because using only uppercase letters (all-caps) reduces legibility.""", ), direction="column", spacing="4", ), type="always", scrollbars="vertical", style={"height": 180}, ) ``` ## Control the scrollable axes Use the `scrollbars` prop to limit scrollable axes. This prop can take values `"vertical" | "horizontal" | "both"`. ```python demo rx.grid( rx.scroll_area( rx.flex( rx.text( """Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense "legible" and "readable" are often used synonymously, typographically they are separate but related concepts.""", size="2", trim="both", ), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as "the quality of being decipherable and recognisable". For instance, if a "b" and an "h", or a "3" and an "8", are difficult to distinguish at small sizes, this is a problem of legibility.""", size="2", trim="both", ), padding="8px", padding_right="48px", direction="column", spacing="4", ), type="always", scrollbars="vertical", style={"height": 150}, ), rx.scroll_area( rx.flex( rx.text( """Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense "legible" and "readable" are often used synonymously, typographically they are separate but related concepts.""", size="2", trim="both", ), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as "the quality of being decipherable and recognisable". For instance, if a "b" and an "h", or a "3" and an "8", are difficult to distinguish at small sizes, this is a problem of legibility.""", size="2", trim="both", ), padding="8px", spacing="4", style={"width": 700}, ), type="always", scrollbars="horizontal", style={"height": 150}, ), rx.scroll_area( rx.flex( rx.text( """Three fundamental aspects of typography are legibility, readability, and aesthetics. Although in a non-technical sense "legible" and "readable" are often used synonymously, typographically they are separate but related concepts.""", size="2", trim="both", ), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as "the quality of being decipherable and recognisable". For instance, if a "b" and an "h", or a "3" and an "8", are difficult to distinguish at small sizes, this is a problem of legibility.""", size="2", trim="both", ), padding="8px", spacing="4", style={"width": 400}, ), type="always", scrollbars="both", style={"height": 150}, ), columns="3", spacing="2", ) ``` ## Setting the type of the Scrollbars The `type` prop describes the nature of scrollbar visibility. `auto` means that scrollbars are visible when content is overflowing on the corresponding orientation. `always` means that scrollbars are always visible regardless of whether the content is overflowing. `scroll` means that scrollbars are visible when the user is scrolling along its corresponding orientation. `hover` when the user is scrolling along its corresponding orientation and when the user is hovering over the scroll area. ```python demo rx.grid( rx.scroll_area( rx.flex( rx.text("type = 'auto'", weight="bold"), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as "the quality of being decipherable and recognisable". For instance, if a "b" and an "h", or a "3" and an "8", are difficult to distinguish at small sizes, this is a problem of legibility.""", size="2", trim="both", ), padding="8px", direction="column", spacing="4", ), type="auto", scrollbars="vertical", style={"height": 150}, ), rx.scroll_area( rx.flex( rx.text("type = 'always'", weight="bold"), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as "the quality of being decipherable and recognisable". For instance, if a "b" and an "h", or a "3" and an "8", are difficult to distinguish at small sizes, this is a problem of legibility.""", size="2", trim="both", ), padding="8px", direction="column", spacing="4", ), type="always", scrollbars="vertical", style={"height": 150}, ), rx.scroll_area( rx.flex( rx.text("type = 'scroll'", weight="bold"), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as "the quality of being decipherable and recognisable". For instance, if a "b" and an "h", or a "3" and an "8", are difficult to distinguish at small sizes, this is a problem of legibility.""", size="2", trim="both", ), padding="8px", direction="column", spacing="4", ), type="scroll", scrollbars="vertical", style={"height": 150}, ), rx.scroll_area( rx.flex( rx.text("type = 'hover'", weight="bold"), rx.text( """Legibility describes how easily individual characters can be distinguished from one another. It is described by Walter Tracy as "the quality of being decipherable and recognisable". For instance, if a "b" and an "h", or a "3" and an "8", are difficult to distinguish at small sizes, this is a problem of legibility.""", size="2", trim="both", ), padding="8px", direction="column", spacing="4", ), type="hover", scrollbars="vertical", style={"height": 150}, ), columns="4", spacing="2", ) ``` ## API Reference ### rx.scroll_area Custom styled, cross-browser scrollable area using native functionality. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `scrollbars` | Literal["vertical", "horizontal", "both"] | - | The alignment of the scroll area. | | `type` | Literal["auto", "always", "scroll", "hover"] | - | Describes the nature of scrollbar visibility, similar to how the scrollbar preferences in MacOS control visibility of native scrollbars. "auto", "always", "scroll", "hover". | | `scroll_hide_delay` | int | - | If type is set to either "scroll" or "hover", this prop determines the length of time, in milliseconds, before the scrollbars are hidden after the user stops interacting with scrollbars. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Spinner Source: http://localhost:3000/docs/library/data-display/spinner.md --- components: - rx.spinner --- Spinner is used to display an animated loading indicator when a task is in progress. ```python exec import reflex as rx ``` ```python demo rx.spinner() ``` ## Basic Examples Spinner can have different sizes. ```python demo rx.vstack( rx.hstack( rx.spinner(size="1"), rx.spinner(size="2"), rx.spinner(size="3"), align="center", gap="1em", ) ) ``` ## Demo with buttons Buttons have their own loading prop that automatically composes a spinner. ```python demo rx.button("Bookmark", loading=True) ``` ## Spinner inside a button If you have an icon inside the button, you can use the button's disabled state and wrap the icon in a standalone rx.spinner to achieve a more sophisticated design. ```python demo rx.button(rx.spinner(loading=True), "Bookmark", disabled=True) ``` ## API Reference ### rx.spinner A spinner component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `loading` | bool | - | If set, show an rx.spinner instead of the component children. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the spinner. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Accordion Source: http://localhost:3000/docs/library/disclosure/accordion.md --- components: - rx.accordion.root - rx.accordion.item AccordionRoot: | lambda **props: rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content", **props, ), rx.accordion.item( header="Second Item", content="The second accordion item's content", **props, ), rx.accordion.item( header="Third item", content="The third accordion item's content", **props, ), width="300px", **props, ) AccordionItem: | lambda **props: rx.accordion.root( rx.accordion.item( header="Single Item", content="The accordion item's content", **props, ), width="300px", ) --- ```python exec import reflex as rx ``` An accordion is a vertically stacked set of interactive headings that each reveal an associated section of content. The accordion component is made up of `accordion`, which is the root of the component and takes in an `accordion.item`, which contains all the contents of the collapsible section. ## Basic Example ```python demo rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), width="300px", ) ``` ## Styling ### Type We use the `type` prop to determine whether multiple items can be opened at once. The allowed values for this prop are `single` and `multiple` where `single` will only open one item at a time. The default value for this prop is `single`. ```python demo rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, width="300px", type="multiple", ) ``` ### Default Value We use the `default_value` prop to specify which item should open by default. The value for this prop should be any of the unique values set by an `accordion.item`. ```python demo rx.flex( rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content", value="item_1", ), rx.accordion.item( header="Second Item", content="The second accordion item's content", value="item_2", ), rx.accordion.item( header="Third item", content="The third accordion item's content", value="item_3", ), width="300px", default_value="item_2", ), direction="row", spacing="2", ) ``` ### Collapsible We use the `collapsible` prop to allow all items to close. If set to `False`, an opened item cannot be closed. ```python demo rx.flex( rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content" ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, width="300px", ), rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content" ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=False, width="300px", ), direction="row", spacing="2", ) ``` ### Disable We use the `disabled` prop to prevent interaction with the accordion and all its items. ```python demo rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content" ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, width="300px", disabled=True, ) ``` ### Orientation We use `orientation` prop to set the orientation of the accordion to `vertical` or `horizontal`. By default, the orientation will be set to `vertical`. Note that, the orientation prop won't change the visual orientation but the functional orientation of the accordion. This means that for vertical orientation, the up and down arrow keys moves focus between the next or previous item, while for horizontal orientation, the left or right arrow keys moves focus between items. ```python demo rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, width="300px", orientation="vertical", ) ``` ```python demo rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, width="300px", orientation="horizontal", ) ``` ### Variant ```python demo rx.flex( rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, variant="classic", ), rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, variant="soft", ), rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, variant="outline", ), rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, variant="surface", ), rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, variant="ghost", ), direction="row", spacing="2", ) ``` ### Color Scheme We use the `color_scheme` prop to assign a specific color to the accordion background, ignoring the global theme. ```python demo rx.flex( rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, width="300px", color_scheme="grass", ), rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content" ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, width="300px", color_scheme="green", ), direction="row", spacing="2", ) ``` ### Value We use the `value` prop to specify the controlled value of the accordion item that we want to activate. This property should be used in conjunction with the `on_value_change` event argument. ```python demo exec class AccordionState(rx.State): """The app state.""" value: str = "item_1" item_selected: str @rx.event def change_value(self, value): self.value = value self.item_selected = f"{value} selected" def index() -> rx.Component: return rx.theme( rx.container( rx.text(AccordionState.item_selected), rx.flex( rx.accordion.root( rx.accordion.item( header="Is it accessible?", content=rx.button("Test button"), value="item_1", ), rx.accordion.item( header="Is it unstyled?", content="Yes. It's unstyled by default, giving you freedom over the look and feel.", value="item_2", ), rx.accordion.item( header="Is it finished?", content="It's still in beta, but it's ready to use in production.", value="item_3", ), collapsible=True, width="300px", value=AccordionState.value, on_value_change=lambda value: AccordionState.change_value(value), ), direction="column", spacing="2", ), padding="2em", text_align="center", ) ) ``` ## AccordionItem The accordion item contains all the parts of a collapsible section. ## Styling ### Value ```python demo rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content", value="item_1", ), rx.accordion.item( header="Second Item", content="The second accordion item's content", value="item_2", ), rx.accordion.item( header="Third item", content="The third accordion item's content", value="item_3", ), collapsible=True, width="300px", ) ``` ### Disable ```python demo rx.accordion.root( rx.accordion.item( header="First Item", content="The first accordion item's content", disabled=True, ), rx.accordion.item( header="Second Item", content="The second accordion item's content", ), rx.accordion.item( header="Third item", content="The third accordion item's content" ), collapsible=True, width="300px", color_scheme="blue", ) ``` ## API Reference ### rx.accordion.root An accordion component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color scheme of the component. | | `variant` | Literal["classic", "soft", "surface", "outline", "ghost"] | - | The variant of the component. | | `type` | Literal["single", "multiple"] | - | The type of accordion (single or multiple). | | `value` | str, Sequence[str] | - | The value of the item to expand. | | `default_value` | str, Sequence[str] | - | The default value of the item to expand. | | `collapsible` | bool | - | Whether or not the accordion is collapsible. | | `disabled` | bool | - | Whether or not the accordion is disabled. | | `dir` | Literal["ltr", "rtl"] | - | The reading direction of the accordion when applicable. | | `orientation` | Literal["vertical", "horizontal"] | - | The orientation of the accordion. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | The radius of the accordion corners. | | `duration` | int | - | The time in milliseconds to animate open and close. | | `easing` | str | - | The easing function to use for the animation. | | `show_dividers` | bool | - | Whether to show divider lines between items. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_value_change` | Fired when the opened the accordions changes. | ### rx.accordion.item An accordion component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color scheme of the component. | | `variant` | Literal["classic", "soft", "surface", "outline", "ghost"] | - | The variant of the component. | | `value` | str | - | A unique identifier for the item. | | `disabled` | bool | - | When true, prevents the user from interacting with the item. | | `header` | Component, str | - | The header of the accordion item. | | `content` | str, Component, NoneType | - | The content of the accordion item. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Segmented Control Source: http://localhost:3000/docs/library/disclosure/segmented-control.md --- components: - rx.segmented_control.root - rx.segmented_control.item SegmentedControlRoot: | lambda **props: rx.segmented_control.root( rx.segmented_control.item("Inbox", value="inbox"), rx.segmented_control.item("Drafts", value="drafts"), rx.segmented_control.item("Sent", value="sent"), default_value="inbox", **props, ) SegmentedControlItem: | lambda **props: rx.segmented_control.root( rx.segmented_control.item("Inbox", value="inbox", **props), rx.segmented_control.item("Drafts", value="drafts"), default_value="inbox", ) --- ```python exec import reflex as rx class SegmentedState(rx.State): """The app state.""" control: str = "test" @rx.event def set_control(self, value: str | list[str]): self.control = value ``` Segmented Control offers a clear and accessible way to switch between predefined values and views, e.g., "Inbox," "Drafts," and "Sent." With Segmented Control, you can make mutually exclusive choices, where only one option can be active at a time, clear and accessible. Without Segmented Control, end users might have to deal with controls like dropdowns or multiple buttons that don't clearly convey state or group options together visually. ## Basic Example The `Segmented Control` component is made up of a `rx.segmented_control.root` which groups `rx.segmented_control.item`. The `rx.segmented_control.item` components define the individual segments of the control, each with a label and a unique value. ```python demo rx.vstack( rx.segmented_control.root( rx.segmented_control.item("Home", value="home"), rx.segmented_control.item("About", value="about"), rx.segmented_control.item("Test", value="test"), on_change=SegmentedState.set_control, value=SegmentedState.control, ), rx.card( rx.text(SegmentedState.control, align="left"), rx.text(SegmentedState.control, align="center"), rx.text(SegmentedState.control, align="right"), width="100%", ), ) ``` **In the example above:** `on_change` is used to specify a callback function that will be called when the user selects a different segment. In this case, the `SegmentedState.setvar("control")` function is used to update the `control` state variable when the user changes the selected segment. `value` prop is used to specify the currently selected segment, which is bound to the `SegmentedState.control` state variable. ## API Reference ### rx.segmented_control.root Root element for a SegmentedControl component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the segmented control: "1", "2", "3". | | `variant` | Literal["classic", "surface"] | - | Variant of button: "classic", "surface". | | `type` | Literal["single", "multiple"] | - | The type of the segmented control, either "single" for selecting one option or "multiple" for selecting multiple options. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for button. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | The radius of the segmented control: "none", "small", "medium", "large", "full". | | `default_value` | str, Sequence[str] | - | The default value of the segmented control. | | `value` | str, Sequence[str] | - | The current value of the segmented control. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Handles the `onChange` event for the SegmentedControl component. | ### rx.segmented_control.item An item in the SegmentedControl component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | str | - | The value of the item. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Tabs Source: http://localhost:3000/docs/library/disclosure/tabs.md --- components: - rx.tabs.root - rx.tabs.list - rx.tabs.trigger - rx.tabs.content only_low_level: - True TabsRoot: | lambda **props: rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Account", value="account"), rx.tabs.trigger("Documents", value="documents"), rx.tabs.trigger("Settings", value="settings"), ), rx.box( rx.tabs.content( rx.text("Make changes to your account"), value="account", ), rx.tabs.content( rx.text("Update your documents"), value="documents", ), rx.tabs.content( rx.text("Edit your personal profile"), value="settings", ), ), **props, ) TabsList: | lambda **props: rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Account", value="account"), rx.tabs.trigger("Documents", value="documents"), rx.tabs.trigger("Settings", value="settings"), **props, ), rx.box( rx.tabs.content( rx.text("Make changes to your account"), value="account", ), rx.tabs.content( rx.text("Update your documents"), value="documents", ), rx.tabs.content( rx.text("Edit your personal profile"), value="settings", ), ), ) TabsTrigger: | lambda **props: rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Account", value="account", **props), rx.tabs.trigger("Documents", value="documents", **props), rx.tabs.trigger("Settings", value="settings", **props), ), rx.box( rx.tabs.content( rx.text("Make changes to your account"), value="account", ), rx.tabs.content( rx.text("Update your documents"), value="documents", ), rx.tabs.content( rx.text("Edit your personal profile"), value="settings", ), ), ) TabsContent: | lambda **props: rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Account", value="account"), rx.tabs.trigger("Documents", value="documents"), rx.tabs.trigger("Settings", value="settings"), ), rx.box( rx.tabs.content( rx.text("Make changes to your account"), value="account", **props, ), rx.tabs.content( rx.text("Update your documents"), value="documents", **props, ), rx.tabs.content( rx.text("Edit your personal profile"), value="settings", **props, ), ), ) --- ```python exec import reflex as rx ``` Tabs are a set of layered sections of content—known as tab panels that are displayed one at a time. They facilitate the organization and navigation between sets of content that share a connection and exist at a similar level of hierarchy. ## Basic Example ```python demo rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Tab 1", value="tab1"), rx.tabs.trigger("Tab 2", value="tab2") ), rx.tabs.content( rx.text("item on tab 1"), value="tab1", ), rx.tabs.content( rx.text("item on tab 2"), value="tab2", ), ) ``` The `tabs` component is made up of a `rx.tabs.root` which groups `rx.tabs.list` and `rx.tabs.content` parts. ## Styling ### Default value We use the `default_value` prop to set a default active tab, this will select the specified tab by default. ```python demo rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Tab 1", value="tab1"), rx.tabs.trigger("Tab 2", value="tab2") ), rx.tabs.content( rx.text("item on tab 1"), value="tab1", ), rx.tabs.content( rx.text("item on tab 2"), value="tab2", ), default_value="tab2", ) ``` ### Orientation We use `orientation` prop to set the orientation of the tabs component to `vertical` or `horizontal`. By default, the orientation will be set to `horizontal`. Setting this value will change both the visual orientation and the functional orientation. ```md alert info The functional orientation means for `vertical`, the `up` and `down` arrow keys moves focus between the next or previous tab, while for `horizontal`, the `left` and `right` arrow keys moves focus between tabs. ``` ```md alert warning # When using vertical orientation, make sure to assign a tabs.content for each trigger. Defining triggers without content will result in a visual bug where the width of the triggers list isn't constant. ``` ```python demo rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Tab 1", value="tab1"), rx.tabs.trigger("Tab 2", value="tab2") ), rx.tabs.content( rx.text("item on tab 1"), value="tab1", ), rx.tabs.content( rx.text("item on tab 2"), value="tab2", ), default_value="tab1", orientation="vertical", ) ``` ```python demo rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Tab 1", value="tab1"), rx.tabs.trigger("Tab 2", value="tab2") ), rx.tabs.content( rx.text("item on tab 1"), value="tab1", ), rx.tabs.content( rx.text("item on tab 2"), value="tab2", ), default_value="tab1", orientation="horizontal", ) ``` ### Value We use the `value` prop to specify the controlled value of the tab that we want to activate. This property should be used in conjunction with the `on_change` event argument. ```python demo exec class TabsState(rx.State): """The app state.""" value = "tab1" tab_selected = "" @rx.event def change_value(self, val): self.tab_selected = f"{val} clicked!" self.value = val def index() -> rx.Component: return rx.container( rx.flex( rx.text(f"{TabsState.value} clicked !"), rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Tab 1", value="tab1"), rx.tabs.trigger("Tab 2", value="tab2"), ), rx.tabs.content( rx.text("items on tab 1"), value="tab1", ), rx.tabs.content( rx.text("items on tab 2"), value="tab2", ), default_value="tab1", value=TabsState.value, on_change=lambda x: TabsState.change_value(x), ), direction="column", spacing="2", ), padding="2em", font_size="2em", text_align="center", ) ``` ## Tablist The Tablist is used to list the respective tabs to the tab component ## Tab Trigger This is the button that activates the tab's associated content. It is typically used in the `Tablist` ## Styling ### Value We use the `value` prop to assign a unique value that associates the trigger with content. ```python demo rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Tab 1", value="tab1"), rx.tabs.trigger("Tab 2", value="tab2"), rx.tabs.trigger("Tab 3", value="tab3"), ), ) ``` ### Disable We use the `disabled` prop to disable the tab. ```python demo rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Tab 1", value="tab1"), rx.tabs.trigger("Tab 2", value="tab2"), rx.tabs.trigger("Tab 3", value="tab3", disabled=True), ), ) ``` ## Tabs Content Contains the content associated with each trigger. ## Styling ### Value We use the `value` prop to assign a unique value that associates the content with a trigger. ```python rx.tabs.root( rx.tabs.list( rx.tabs.trigger("Tab 1", value="tab1"), rx.tabs.trigger("Tab 2", value="tab2") ), rx.tabs.content( rx.text("item on tab 1"), value="tab1", ), rx.tabs.content( rx.text("item on tab 2"), value="tab2", ), default_value="tab1", orientation="vertical", ) ``` ## API Reference ### rx.tabs.root Set of content sections to be displayed one at a time. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `default_value` | str | - | The value of the tab that should be active when initially rendered. Use when you do not need to control the state of the tabs. | | `value` | str | - | The controlled value of the tab that should be active. Use when you need to control the state of the tabs. | | `orientation` | Literal["vertical", "horizontal"] | - | The orientation of the tabs. | | `dir` | Literal["ltr", "rtl"] | - | Reading direction of the tabs. | | `activation_mode` | Literal["automatic", "manual"] | - | The mode of activation for the tabs. "automatic" will activate the tab when focused. "manual" will activate the tab when clicked. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fired when the value of the tabs changes. | ### rx.tabs.list Contains the triggers that sit alongside the active content. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | Literal["1", "2"], Breakpoints[str, Literal["1", "2"]] | - | Tabs size "1" - "2". | | `loop` | bool | - | When true, the tabs will loop when reaching the end. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.tabs.trigger The button that activates its associated content. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | str | - | The value of the tab. Must be unique for each tab. | | `disabled` | bool | - | Whether the tab is disabled. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color of the line under the tab when active. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.tabs.content Contains the content associated with each trigger. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | str | - | The value of the tab. Must be unique for each tab. | | `force_mount` | bool | - | Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Auto Scroll Source: http://localhost:3000/docs/library/dynamic-rendering/auto-scroll.md --- components: - rx.auto_scroll --- ```python exec import reflex as rx ``` The `rx.auto_scroll` component is a div that automatically scrolls to the bottom when new content is added. This is useful for chat interfaces, logs, or any container where new content is dynamically added and you want to ensure the most recent content is visible. ## Basic Usage ```python demo exec import reflex as rx class AutoScrollState(rx.State): messages: list[str] = ["Initial message"] def add_message(self): self.messages.append(f"New message #{len(self.messages) + 1}") def auto_scroll_example(): return rx.vstack( rx.auto_scroll( rx.foreach( AutoScrollState.messages, lambda message: rx.box( message, padding="0.5em", border_bottom="1px solid #eee", width="100%", ), ), height="200px", width="300px", border="1px solid #ddd", border_radius="md", ), rx.button("Add Message", on_click=AutoScrollState.add_message), width="300px", align_items="center", ) ``` The `auto_scroll` component automatically scrolls to show the newest content when it's added. In this example, each time you click "Add Message", a new message is added to the list and the container automatically scrolls to display it. ## When to Use Auto Scroll - **Chat applications**: Keep the chat window scrolled to the most recent messages. - **Log viewers**: Automatically follow new log entries as they appear. - **Feed interfaces**: Keep the newest content visible in dynamically updating feeds. ## Props `rx.auto_scroll` is based on the `rx.div` component and inherits all of its props. By default, it sets `overflow="auto"` to enable scrolling. Some common props you might use with `auto_scroll`: - `height`: Set the height of the scrollable container. - `width`: Set the width of the scrollable container. - `padding`: Add padding inside the container. - `border`: Add a border around the container. - `border_radius`: Round the corners of the container. ## How It Works The component tracks when new content is added and maintains the scroll position in two scenarios: 1. When the user is already near the bottom of the content (within 50 pixels), it will scroll to the bottom when new content is added. 2. When the container didn't have a scrollbar before but does now (due to new content), it will automatically scroll to the bottom. This behavior ensures that users can scroll up to view older content without being forced back to the bottom, while still automatically following new content in most cases. ## API Reference ### rx.auto_scroll A div that automatically scrolls to the bottom when new content is added. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Cond Source: http://localhost:3000/docs/library/dynamic-rendering/cond.md --- components: - rx.cond --- ```python exec import reflex as rx ``` This component is used to conditionally render components. The cond component takes a condition and two components. If the condition is `True`, the first component is rendered, otherwise the second component is rendered. ```python demo exec class CondState(rx.State): show: bool = True @rx.event def change(self): self.show = not (self.show) def cond_example(): return rx.vstack( rx.button("Toggle", on_click=CondState.change), rx.cond( CondState.show, rx.text("Text 1", color="blue"), rx.text("Text 2", color="red"), ), ) ``` The second component is optional and can be omitted. If it is omitted, nothing is rendered if the condition is `False`. ```python demo exec class CondOptionalState(rx.State): show_optional: bool = True @rx.event def toggle_optional(self): self.show_optional = not (self.show_optional) def cond_optional_example(): return rx.vstack( rx.button("Toggle", on_click=CondOptionalState.toggle_optional), rx.cond( CondOptionalState.show_optional, rx.text("This text appears when condition is True", color="green"), ), rx.text("This text is always visible", color="gray"), ) ``` ```md video https://youtube.com/embed/ITOZkzjtjUA?start=6040&end=6463 # Video: Conditional Rendering ``` ## Negation You can use the logical operator `~` to negate a condition. ```python rx.vstack( rx.button("Toggle", on_click=CondState.change), rx.cond( CondState.show, rx.text("Text 1", color="blue"), rx.text("Text 2", color="red") ), rx.cond( ~CondState.show, rx.text("Text 1", color="blue"), rx.text("Text 2", color="red") ), ) ``` ## Multiple Conditions It is also possible to make up complex conditions using the `logical or` (|) and `logical and` (&) operators. Here we have an example using the var operators `>=`, `<=`, `&`. We define a condition that if a person has an age between 18 and 65, including those ages, they are able to work, otherwise they cannot. We could equally use the operator `|` to represent a `logical or` in one of our conditions. ```python demo exec import random class CondComplexState(rx.State): age: int = 19 @rx.event def change(self): self.age = random.randint(0, 100) def cond_complex_example(): return rx.vstack( rx.button("Toggle", on_click=CondComplexState.change), rx.text(f"Age: {CondComplexState.age}"), rx.cond( (CondComplexState.age >= 18) & (CondComplexState.age <= 65), rx.text("You can work!", color="green"), rx.text("You cannot work!", color="red"), ), ) ``` ## Nested Conditional We can also nest `cond` components within each other to create more complex logic. In python we can have an `if` statement that then has several `elif` statements before finishing with an `else`. This is also possible in reflex using nested `cond` components. In this example we check whether a number is positive, negative or zero. Here is the python logic using `if` statements: ```python number = 0 if number > 0: print("Positive number") elif number == 0: print("Zero") else: print("Negative number") ``` This reflex code that is logically identical: ```python demo exec import random class NestedState(rx.State): num: int = 0 def change(self): self.num = random.randint(-10, 10) def cond_nested_example(): return rx.vstack( rx.button("Toggle", on_click=NestedState.change), rx.cond( NestedState.num > 0, rx.text(f"{NestedState.num} is Positive!", color="orange"), rx.cond( NestedState.num == 0, rx.text(f"{NestedState.num} is Zero!", color="blue"), rx.text(f"{NestedState.num} is Negative!", color="red"), ), ), ) ``` Here is a more advanced example where we have three numbers and we are checking which of the three is the largest. If any two of them are equal then we return that `Some of the numbers are equal!`. The reflex code that follows is logically identical to doing the following in python: ```python a = 8 b = 10 c = 2 if (a > b and a > c) and (a != b and a != c): print(a, " is the largest!") elif (b > a and b > c) and (b != a and b != c): print(b, " is the largest!") elif (c > a and c > b) and (c != a and c != b): print(c, " is the largest!") else: print("Some of the numbers are equal!") ``` ## API Reference ### rx.cond Render one of two components based on a condition. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `cond` | Any | - | The cond to determine which component to render. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Foreach Source: http://localhost:3000/docs/library/dynamic-rendering/foreach.md --- components: - rx.foreach --- ```python exec import reflex as rx ``` The `rx.foreach` component takes an iterable(list, tuple or dict) and a function that renders each item in the list. This is useful for dynamically rendering a list of items defined in a state. ```md alert warning # `rx.foreach` is specialized for usecases where the iterable is defined in a state var. For an iterable where the content doesn't change at runtime, i.e a constant, using a list/dict comprehension instead of `rx.foreach` is preferred. ``` ```python demo exec from typing import List class ForeachState(rx.State): color: List[str] = ["red", "green", "blue", "yellow", "orange", "purple"] def colored_box(color: str): return rx.box(rx.text(color), bg=color) def foreach_example(): return rx.grid( rx.foreach(ForeachState.color, colored_box), columns="2", ) ``` The function can also take an index as a second argument. ```python demo exec def colored_box_index(color: str, index: int): return rx.box(rx.text(index), bg=color) def foreach_example_index(): return rx.grid( rx.foreach( ForeachState.color, lambda color, index: colored_box_index(color, index) ), columns="2", ) ``` Nested foreach components can be used to render nested lists. When indexing into a nested list, it's important to declare the list's type as Reflex requires it for type checking. This ensures that any potential frontend JS errors are caught before the user can encounter them. ```python demo exec from typing import List class NestedForeachState(rx.State): numbers: List[List[str]] = [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]] def display_row(row): return rx.hstack( rx.foreach( row, lambda item: rx.box( item, border="1px solid black", padding="0.5em", ), ), ) def nested_foreach_example(): return rx.vstack(rx.foreach(NestedForeachState.numbers, display_row)) ``` Below is a more complex example of foreach within a todo list. ```python demo exec from typing import List class ListState(rx.State): items: List[str] = ["Write Code", "Sleep", "Have Fun"] new_item: str @rx.event def set_new_item(self, new_item: str): self.new_item = new_item @rx.event def add_item(self): self.items += [self.new_item] def finish_item(self, item: str): self.items = [i for i in self.items if i != item] def get_item(item): return rx.list.item( rx.hstack( rx.button( on_click=lambda: ListState.finish_item(item), height="1.5em", background_color="white", border="1px solid blue", ), rx.text(item, font_size="1.25em"), ), ) def todo_example(): return rx.vstack( rx.heading("Todos"), rx.input( on_blur=ListState.set_new_item, placeholder="Add a todo...", bg="white" ), rx.button("Add", on_click=ListState.add_item, bg="white"), rx.divider(), rx.list.ordered( rx.foreach( ListState.items, get_item, ), ), bg="#ededed", padding="1em", border_radius="0.5em", shadow="lg", ) ``` ## Dictionaries Items in a dictionary can be accessed as list of key-value pairs. Using the color example, we can slightly modify the code to use dicts as shown below. ```python demo exec from typing import List class SimpleDictForeachState(rx.State): color_chart: dict[int, str] = {1: "blue", 2: "red", 3: "green"} def display_color(color: List): # color is presented as a list key-value pair([1, "blue"],[2, "red"], [3, "green"]) return rx.box(rx.text(color[0]), bg=color[1]) def foreach_dict_example(): return rx.grid( rx.foreach(SimpleDictForeachState.color_chart, display_color), columns="2" ) ``` Now let's show a more complex example with dicts using the color example. Assuming we want to display a dictionary of secondary colors as keys and their constituent primary colors as values, we can modify the code as below: ```python demo exec from typing import List, Dict class ComplexDictForeachState(rx.State): color_chart: Dict[str, List[str]] = { "purple": ["red", "blue"], "orange": ["yellow", "red"], "green": ["blue", "yellow"], } def display_colors(color: List): return rx.vstack( rx.text(color[0], color=color[0]), rx.hstack( rx.foreach(color[1], lambda x: rx.box(rx.text(x, color="black"), bg=x)) ), ) def foreach_complex_dict_example(): return rx.grid( rx.foreach(ComplexDictForeachState.color_chart, display_colors), columns="2" ) ``` ## API Reference ### rx.foreach A component that takes in an iterable and a render function and renders a list of components. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `iterable` | Iterable | - | The iterable to create components from. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Match Source: http://localhost:3000/docs/library/dynamic-rendering/match.md --- components: - rx.match --- ```python exec import reflex as rx ``` The `rx.match` feature in Reflex serves as a powerful alternative to `rx.cond` for handling conditional statements. While `rx.cond` excels at conditionally rendering two components based on a single condition, `rx.match` extends this functionality by allowing developers to handle multiple conditions and their associated components. This feature is especially valuable when dealing with intricate conditional logic or nested scenarios, where the limitations of `rx.cond` might lead to less readable and more complex code. With `rx.match`, developers can not only handle multiple conditions but also perform structural pattern matching, making it a versatile tool for managing various scenarios in Reflex applications. ## Basic Usage The `rx.match` function provides a clear and expressive syntax for handling multiple conditions and their corresponding components: ```python rx.match( condition, (case_1, component_1), (case_2, component_2), ... default_component, ) ``` - `condition`: The value to match against. - `(case_i, component_i)`: A Tuple of matching cases and their corresponding return components. - `default_component`: A special case for the default component when the condition isn't matched by any of the match cases. Example ```python demo exec from typing import List import reflex as rx class MatchState(rx.State): cat_breed: str = "" animal_options: List[str] = [ "persian", "siamese", "maine coon", "ragdoll", "pug", "corgi", ] @rx.event def set_cat_breed(self, breed: str): self.cat_breed = breed def match_demo(): return rx.flex( rx.match( MatchState.cat_breed, ("persian", rx.text("Persian cat selected.")), ("siamese", rx.text("Siamese cat selected.")), ("maine coon", rx.text("Maine Coon cat selected.")), ("ragdoll", rx.text("Ragdoll cat selected.")), rx.text("Unknown cat breed selected."), ), rx.select.root( rx.select.trigger(), rx.select.content( rx.select.group( rx.foreach( MatchState.animal_options, lambda x: rx.select.item(x, value=x) ) ), ), value=MatchState.cat_breed, on_change=MatchState.set_cat_breed, ), direction="column", gap="2", ) ``` ## Default Case The default case in `rx.match` serves as a universal handler for scenarios where none of the specified match cases aligns with the given match condition. Here are key considerations when working with the default case: - **Placement in the Match Function**: The default case must be the last non-tuple argument in the `rx.match` component. All match cases should be enclosed in tuples; any non-tuple value is automatically treated as the default case. For example: ```python rx.match( MatchState.cat_breed, ("persian", rx.text("persian cat selected")), rx.text("Unknown cat breed selected."), ("siamese", rx.text("siamese cat selected")), ) ``` The above code snippet will result in an error due to the misplaced default case. - **Single Default Case**: Only one default case is allowed in the `rx.match` component. Attempting to specify multiple default cases will lead to an error. For instance: ```python rx.match( MatchState.cat_breed, ("persian", rx.text("persian cat selected")), ("siamese", rx.text("siamese cat selected")), rx.text("Unknown cat breed selected."), rx.text("Another unknown cat breed selected."), ) ``` - **Optional Default Case for Component Return Values**: If the match cases in a `rx.match` component return components, the default case can be optional. In this scenario, if a default case is not provided, `rx.fragment` will be implicitly assigned as the default. For example: ```python rx.match( MatchState.cat_breed, ("persian", rx.text("persian cat selected")), ("siamese", rx.text("siamese cat selected")), ) ``` In this case, `rx.fragment` is the default case. However, not providing a default case for non-component return values will result in an error: ```python rx.match( MatchState.cat_breed, ("persian", "persian cat selected"), ("siamese", "siamese cat selected"), ) ``` The above code snippet will result in an error as a default case must be explicitly provided in this scenario. ## Handling Multiple Conditions `rx.match` excels in efficiently managing multiple conditions and their corresponding components, providing a cleaner and more readable alternative compared to nested `rx.cond` structures. Consider the following example: ```python demo exec from typing import List import reflex as rx class MultiMatchState(rx.State): animal_breed: str = "" animal_options: List[str] = [ "persian", "siamese", "maine coon", "pug", "corgi", "mustang", "rahvan", "football", "golf", ] @rx.event def set_animal_breed(self, breed: str): self.animal_breed = breed def multi_match_demo(): return rx.flex( rx.match( MultiMatchState.animal_breed, ("persian", "siamese", "maine coon", rx.text("Breeds of cats.")), ("pug", "corgi", rx.text("Breeds of dogs.")), ("mustang", "rahvan", rx.text("Breeds of horses.")), rx.text("Unknown animal breed"), ), rx.select.root( rx.select.trigger(), rx.select.content( rx.select.group( rx.foreach( MultiMatchState.animal_options, lambda x: rx.select.item(x, value=x), ) ), ), value=MultiMatchState.animal_breed, on_change=MultiMatchState.set_animal_breed, ), direction="column", gap="2", ) ``` In a match case tuple, you can specify multiple conditions. The last value of the match case tuple is automatically considered as the return value. It's important to note that a match case tuple should contain a minimum of two elements: a match case and a return value. The following code snippet will result in an error: ```python rx.match( MatchState.cat_breed, ("persian",), ("maine coon", rx.text("Maine Coon cat selected")), ) ``` ## Usage as Props Similar to `rx.cond`, `rx.match` can be used as prop values, allowing dynamic behavior for UI components: ```python demo exec import reflex as rx class MatchPropState(rx.State): value: int = 0 @rx.event def incr(self): self.value += 1 @rx.event def decr(self): self.value -= 1 def match_prop_demo_(): return rx.flex( rx.button("decrement", on_click=MatchPropState.decr, background_color="red"), rx.badge( MatchPropState.value, color_scheme=rx.match( MatchPropState.value, (1, "red"), (2, "blue"), (6, "purple"), (10, "orange"), "green", ), size="2", ), rx.button("increment", on_click=MatchPropState.incr), align_items="center", direction="row", gap="3", ) ``` In the example above, the background color property of the box component containing `State.value` changes to red when `state.value` is 1, blue when its 5, green when its 5, orange when its 15 and black for any other value. The example below also shows handling multiple conditions with the match component as props. ```python demo exec import reflex as rx class MatchMultiPropState(rx.State): value: int = 0 @rx.event def incr(self): self.value += 1 @rx.event def decr(self): self.value -= 1 def match_multi_prop_demo_(): return rx.flex( rx.button( "decrement", on_click=MatchMultiPropState.decr, background_color="red" ), rx.badge( MatchMultiPropState.value, color_scheme=rx.match( MatchMultiPropState.value, (1, 3, 9, "red"), (2, 4, 5, "blue"), (6, 8, 12, "purple"), (10, 15, 20, 25, "orange"), "green", ), size="2", ), rx.button("increment", on_click=MatchMultiPropState.incr), align_items="center", direction="row", gap="3", ) ``` ```md alert warning # Usage with Structural Pattern Matching The `rx.match` component is designed for structural pattern matching. If the value of your match condition evaluates to a boolean (True or False), it is recommended to use `rx.cond` instead. Consider the following example, which is more suitable for `rx.cond`:\* ``` ```python rx.cond(MatchPropState.value == 10, "true value", "false value") ``` ## API Reference ### rx.match Match cases based on a condition. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `cond` | Any | - | The condition to determine which case to match. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Button Source: http://localhost:3000/docs/library/forms/button.md --- components: - rx.button Button: | lambda **props: rx.button("Basic Button", **props) --- ```python exec import reflex as rx ``` Buttons are essential elements in your application's user interface that users can click to trigger events. ## Basic Example The `on_click` trigger is called when the button is clicked. ```python demo exec class CountState(rx.State): count: int = 0 @rx.event def increment(self): self.count += 1 @rx.event def decrement(self): self.count -= 1 def counter(): return rx.flex( rx.button( "Decrement", color_scheme="red", on_click=CountState.decrement, ), rx.heading(CountState.count), rx.button( "Increment", color_scheme="grass", on_click=CountState.increment, ), spacing="3", ) ``` ### Loading and Disabled The `loading` prop is used to indicate that the action triggered by the button is currently in progress. When set to `True`, the button displays a loading spinner, providing visual feedback to the user that the action is being processed. This also prevents multiple clicks while the button is in the loading state. By default, `loading` is set to `False`. The `disabled` prop also prevents the button from being but does not provide a spinner. ```python demo rx.flex( rx.button("Regular"), rx.button("Loading", loading=True), rx.button("Disabled", disabled=True), spacing="2", ) ``` ## API Reference ### rx.button Trigger an action or event, such as submitting a form or displaying a dialog. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `loading` | bool | - | If set, show an rx.spinner instead of the component children. | | `auto_focus` | bool | - | Automatically focuses the button when the page loads. | | `disabled` | bool | - | Disables the button. | | `form` | str | - | Associates the button with a form (by id). | | `form_action` | str | - | URL to send the form data to (for type="submit" buttons). | | `form_enc_type` | str | - | How the form data should be encoded when submitting to the server (for type="submit" buttons). | | `form_method` | str | - | HTTP method to use for sending form data (for type="submit" buttons). | | `form_no_validate` | bool | - | Bypasses form validation when submitting (for type="submit" buttons). | | `form_target` | str | - | Specifies where to display the response after submitting the form (for type="submit" buttons). | | `name` | str | - | Name of the button, used when sending form data. | | `type` | Literal["submit", "reset", "button"] | - | Type of the button (submit, reset, or button). | | `value` | str, int, float | - | Value of the button, used when sending form data. | | `as_child` | bool | - | Change the default rendered element for the one passed as a child, merging their props and behavior. | | `size` | Literal["1", "2", "3", "4"], Breakpoints[str, Literal["1", "2", "3", "4"]] | - | Button size "1" - "4". | | `variant` | Literal["classic", "solid", "soft", "surface", "outline", "ghost"] | - | Variant of button: "solid", "soft", "outline", "ghost". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for button. | | `high_contrast` | bool | - | Whether to render the button with higher contrast color against background. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | Override theme radius for button: "none", "small", "medium", "large", "full". | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Checkbox Source: http://localhost:3000/docs/library/forms/checkbox.md --- components: - rx.checkbox HighLevelCheckbox: | lambda **props: rx.checkbox("Basic Checkbox", **props) --- ```python exec import reflex as rx ``` ## Basic Example The `on_change` trigger is called when the `checkbox` is clicked. ```python demo exec class CheckboxState(rx.State): checked: bool = False @rx.event def set_checked(self, value: bool): self.checked = value def checkbox_example(): return rx.vstack( rx.heading(CheckboxState.checked), rx.checkbox(on_change=CheckboxState.set_checked), ) ``` The `input` prop is used to set the `checkbox` as a controlled component. ```python demo exec class FormCheckboxState(rx.State): form_data: dict = {} @rx.event def handle_submit(self, form_data: dict): """Handle the form submit.""" print(form_data) self.form_data = form_data def form_checkbox_example(): return rx.card( rx.vstack( rx.heading("Example Form"), rx.form.root( rx.hstack( rx.checkbox( name="checkbox", label="Accept terms and conditions", ), rx.button("Submit", type="submit"), width="100%", ), on_submit=FormCheckboxState.handle_submit, reset_on_submit=True, ), rx.divider(), rx.hstack( rx.heading("Results:"), rx.badge(FormCheckboxState.form_data.to_string()), ), align_items="left", width="100%", ), width="50%", ) ``` ## API Reference ### rx.checkbox A checkbox component with a label. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `text` | str | - | The text label for the checkbox. | | `spacing` | Literal["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] | - | The gap between the checkbox and the label. | | `size` | Literal["1", "2", "3"] | - | The size of the checkbox "1" - "3". | | `as_child` | bool | - | Change the default rendered element for the one passed as a child, merging their props and behavior. | | `variant` | Literal["classic", "surface", "soft"] | - | Variant of checkbox: "classic", "surface", "soft". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for checkbox. | | `high_contrast` | bool | - | Whether to render the checkbox with higher contrast color against background. | | `default_checked` | bool | - | Whether the checkbox is checked by default. | | `checked` | bool | - | Whether the checkbox is checked. | | `disabled` | bool | - | Whether the checkbox is disabled. | | `required` | bool | - | Whether the checkbox is required. | | `name` | str | - | The name of the checkbox control when submitting the form. | | `value` | str | - | The value of the checkbox control when submitting the form. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fired when the checkbox is checked or unchecked. | # type attribute is required for "typeMismatch" validation Source: http://localhost:3000/docs/library/forms/form.md --- components: - rx.form - rx.form.root - rx.form.field - rx.form.control - rx.form.label - rx.form.message - rx.form.submit FormRoot: | lambda **props: rx.form.root( rx.form.field( rx.flex( rx.form.label("Email"), rx.form.control( rx.input( placeholder="Email Address", # type attribute is required for "typeMismatch" validation type="email", ), as_child=True, ), rx.form.message("Please enter a valid email"), rx.form.submit( rx.button("Submit"), as_child=True, ), direction="column", spacing="2", align="stretch", ), name="email", ), **props, ) FormField: | lambda **props: rx.form.root( rx.form.field( rx.flex( rx.form.label("Email"), rx.form.control( rx.input( placeholder="Email Address", # type attribute is required for "typeMismatch" validation type="email", ), as_child=True, ), rx.form.message("Please enter a valid email", match="typeMismatch"), rx.form.submit( rx.button("Submit"), as_child=True, ), direction="column", spacing="2", align="stretch", ), **props, ), reset_on_submit=True, ) FormLabel: | lambda **props: rx.form.root( rx.form.field( rx.flex( rx.form.label("Email", **props,), rx.form.control( rx.input( placeholder="Email Address", # type attribute is required for "typeMismatch" validation type="email", ), as_child=True, ), rx.form.message("Please enter a valid email", match="typeMismatch"), rx.form.submit( rx.button("Submit"), as_child=True, ), direction="column", spacing="2", align="stretch", ), ), reset_on_submit=True, ) FormMessage: | lambda **props: rx.form.root( rx.form.field( rx.flex( rx.form.label("Email"), rx.form.control( rx.input( placeholder="Email Address", # type attribute is required for "typeMismatch" validation type="email", ), as_child=True, ), rx.form.message("Please enter a valid email", **props,), rx.form.submit( rx.button("Submit"), as_child=True, ), direction="column", spacing="2", align="stretch", ), name="email", ), on_submit=lambda form_data: rx.window_alert(form_data.to_string()), reset_on_submit=True, ) --- ```python exec import reflex as rx ``` Forms are used to collect user input. The `rx.form` component is used to group inputs and submit them together. The form component's children can be form controls such as `rx.input`, `rx.checkbox`, `rx.slider`, `rx.textarea`, `rx.radio_group`, `rx.select` or `rx.switch`. The controls should have a `name` attribute that is used to identify the control in the form data. The `on_submit` event trigger submits the form data as a dictionary to the `handle_submit` event handler. The form is submitted when the user clicks the submit button or presses enter on the form controls. ```python demo exec class FormState(rx.State): form_data: dict = {} @rx.event def handle_submit(self, form_data: dict): """Handle the form submit.""" self.form_data = form_data def form_example(): return rx.vstack( rx.form( rx.vstack( rx.input(placeholder="First Name", name="first_name"), rx.input(placeholder="Last Name", name="last_name"), rx.hstack( rx.checkbox("Checked", name="check"), rx.switch("Switched", name="switch"), ), rx.button("Submit", type="submit"), ), on_submit=FormState.handle_submit, reset_on_submit=True, ), rx.divider(), rx.heading("Results"), rx.text(FormState.form_data.to_string()), ) ``` ```md alert warning # When using the form you must include a button or input with `type='submit'`. ``` ```md alert info # Using `name` vs `id`. When using the `name` attribute in form controls like `rx.switch`, `rx.radio_group`, and `rx.checkbox`, these controls will only be included in the form data if their values are set (e.g., if the checkbox is checked, the switch is toggled, or a radio option is selected). If you need these controls to be passed in the form data even when their values are not set, you can use the `id` attribute instead of name. The id attribute ensures that the control is always included in the submitted form data, regardless of whether its value is set or not. ``` ```md video https://youtube.com/embed/ITOZkzjtjUA?start=5287&end=6040 # Video: Forms ``` ## Dynamic Forms Forms can be dynamically created by iterating through state vars using `rx.foreach`. This example allows the user to add new fields to the form prior to submit, and all fields will be included in the form data passed to the `handle_submit` function. ```python demo exec class DynamicFormState(rx.State): form_data: dict = {} form_fields: list[str] = ["first_name", "last_name", "email"] @rx.var(cache=True) def form_field_placeholders(self) -> list[str]: return [ " ".join(w.capitalize() for w in field.split("_")) for field in self.form_fields ] @rx.event def add_field(self, form_data: dict): new_field = form_data.get("new_field") if not new_field: return field_name = new_field.strip().lower().replace(" ", "_") self.form_fields.append(field_name) @rx.event def handle_submit(self, form_data: dict): self.form_data = form_data def dynamic_form(): return rx.vstack( rx.form( rx.vstack( rx.foreach( DynamicFormState.form_fields, lambda field, idx: rx.input( placeholder=DynamicFormState.form_field_placeholders[idx], name=field, ), ), rx.button("Submit", type="submit"), ), on_submit=DynamicFormState.handle_submit, reset_on_submit=True, ), rx.form( rx.hstack( rx.input(placeholder="New Field", name="new_field"), rx.button("+", type="submit"), ), on_submit=DynamicFormState.add_field, reset_on_submit=True, ), rx.divider(), rx.heading("Results"), rx.text(DynamicFormState.form_data.to_string()), ) ``` ## API Reference ### rx.form The Form component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | | `accept` | str | - | MIME types the server accepts for file upload. | | `accept_charset` | str | - | Character encodings to be used for form submission. | | `action` | str | - | URL where the form's data should be submitted. | | `auto_complete` | str | - | Whether the form should have autocomplete enabled. | | `enc_type` | str | - | Encoding type for the form data when submitted. | | `method` | str | - | HTTP method to use for form submission. | | `name` | str | - | Name of the form. | | `no_validate` | bool | - | Indicates that the form should not be validated on submit. | | `target` | str | - | Where to display the response after submitting the form. | | `reset_on_submit` | bool | - | If true, the form will be cleared after submit. | | `handle_submit_unique_name` | str | - | The name used to make this form's submit handler function unique. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_submit` | Fired when the form is submitted. | | `on_clear_server_errors` | Fired when the errors are cleared. | ### rx.form.root The root component of a radix form. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | | `accept` | str | - | MIME types the server accepts for file upload. | | `accept_charset` | str | - | Character encodings to be used for form submission. | | `action` | str | - | URL where the form's data should be submitted. | | `auto_complete` | str | - | Whether the form should have autocomplete enabled. | | `enc_type` | str | - | Encoding type for the form data when submitted. | | `method` | str | - | HTTP method to use for form submission. | | `name` | str | - | Name of the form. | | `no_validate` | bool | - | Indicates that the form should not be validated on submit. | | `target` | str | - | Where to display the response after submitting the form. | | `reset_on_submit` | bool | - | If true, the form will be cleared after submit. | | `handle_submit_unique_name` | str | - | The name used to make this form's submit handler function unique. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_submit` | Fired when the form is submitted. | | `on_clear_server_errors` | Fired when the errors are cleared. | ### rx.form.field A form field component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | | `name` | str | - | The name of the form field, that is passed down to the control and used to match with validation messages. | | `server_invalid` | bool | - | Flag to mark the form field as invalid, for server side validation. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.form.control A form control component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.form.label A form label component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.form.message A form message component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | | `name` | str | - | Used to target a specific field by name when rendering outside of a Field part. | | `match` | Literal["badInput", "patternMismatch", "rangeOverflow", "rangeUnderflow", "stepMismatch", "tooLong", "tooShort", "typeMismatch", "valid", "valueMissing"] | - | Used to indicate on which condition the message should be visible. | | `force_match` | bool | - | Forces the message to be shown. This is useful when using server-side validation. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.form.submit A form submit component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Input Source: http://localhost:3000/docs/library/forms/input.md --- components: - rx.input - rx.input.slot TextFieldRoot: | lambda **props: rx.input(placeholder="Search the docs", **props) TextFieldSlot: | lambda **props: rx.input( rx.input.slot( rx.icon(tag="search", height="16", width="16"), **props, ), placeholder="Search the docs", ) --- ```python exec import reflex as rx ``` The `input` component is an input field that users can type into. ```md video https://youtube.com/embed/ITOZkzjtjUA?start=1517&end=1869 # Video: Input ``` ## Basic Example The `on_blur` event handler is called when focus has left the `input` for example, it’s called when the user clicks outside of a focused text input. ```python demo exec class TextfieldBlur(rx.State): text: str = "Hello World!" @rx.event def set_text(self, value: str): self.text = value def blur_example(): return rx.vstack( rx.heading(TextfieldBlur.text), rx.input( placeholder="Search here...", on_blur=TextfieldBlur.set_text, ), ) ``` The `on_change` event handler is called when the `value` of `input` has changed. ```python demo exec class TextfieldControlled(rx.State): text: str = "Hello World!" @rx.event def set_text(self, value: str): self.text = value def controlled_example(): return rx.vstack( rx.heading(TextfieldControlled.text), rx.input( placeholder="Search here...", value=TextfieldControlled.text, on_change=TextfieldControlled.set_text, ), ) ``` Behind the scenes, the input component is implemented as a debounced input to avoid sending individual state updates per character to the backend while the user is still typing. This allows a state variable to directly control the `value` prop from the backend without the user experiencing input lag. ## Input Types The `type` prop controls how the input is rendered (e.g. plain text, password, file picker). It accepts the same values as the native HTML `` attribute, such as: - `"text"` (default) - `"password"` - `"email"` - `"number"` - `"file"` - `"checkbox"` - `"radio"` - `"date"` - `"time"` - `"url"` - `"color"` and several others. See the [MDN reference](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types) for the full list. ```python demo rx.vstack( rx.input(placeholder="Username", type="text"), rx.input(placeholder="Password", type="password"), rx.input(type="date"), ) ``` ## Submitting a form using input The `name` prop is needed to submit with its owning form as part of a name/value pair. When the `required` prop is `True`, it indicates that the user must input text before the owning form can be submitted. The `type` is set here to `password`. The element is presented as a one-line plain text editor control in which the text is obscured so that it cannot be read. The `type` prop can take any value of `email`, `file`, `password`, `text` and several others. Learn more [here](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). ```python demo exec class FormInputState(rx.State): form_data: dict = {} @rx.event def handle_submit(self, form_data: dict): """Handle the form submit.""" self.form_data = form_data def form_input1(): return rx.card( rx.vstack( rx.heading("Example Form"), rx.form.root( rx.hstack( rx.input( name="input", placeholder="Enter text...", type="text", required=True, ), rx.button("Submit", type="submit"), width="100%", ), on_submit=FormInputState.handle_submit, reset_on_submit=True, ), rx.divider(), rx.hstack( rx.heading("Results:"), rx.badge(FormInputState.form_data.to_string()), ), align_items="left", width="100%", ), width="50%", ) ``` To learn more about how to use forms in the [Form](/docs/library/forms/form) docs. ## Setting a value without using a State var Set the value of the specified reference element, without needing to link it up to a State var. This is an alternate way to modify the value of the `input`. ```python demo rx.hstack( rx.input(id="input1"), rx.button("Erase", on_click=rx.set_value("input1", "")), ) ``` ## API Reference ### rx.input Captures user input with an optional slot for buttons and icons. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `accept` | str | - | Accepted types of files when the input is file type. | | `alt` | str | - | Alternate text for input type="image". | | `auto_complete` | bool | - | Whether the input should have autocomplete enabled. | | `auto_focus` | bool | - | Automatically focuses the input when the page loads. | | `capture` | Literal["user", "environment"], bool | - | Captures media from the user (camera or microphone). | | `checked` | bool | - | Indicates whether the input is checked (for checkboxes and radio buttons). | | `default_checked` | bool | - | The initial value (for checkboxes and radio buttons). | | `default_value` | str | - | The value of the input when initially rendered. | | `disabled` | bool | - | Disables the input. | | `form` | str | - | Associates the input with a form (by id). | | `form_action` | str | - | URL to send the form data to (for type="submit" buttons). | | `form_enc_type` | str | - | How the form data should be encoded when submitting to the server (for type="submit" buttons). | | `form_method` | str | - | HTTP method to use for sending form data (for type="submit" buttons). | | `form_no_validate` | bool | - | Bypasses form validation when submitting (for type="submit" buttons). | | `form_target` | str | - | Specifies where to display the response after submitting the form (for type="submit" buttons). | | `list` | str | - | References a datalist for suggested options. | | `max` | str, int, float | - | Specifies the maximum value for the input. | | `max_length` | int | - | Specifies the maximum number of characters allowed in the input. | | `min_length` | int | - | Specifies the minimum number of characters required in the input. | | `min` | str, int, float | - | Specifies the minimum value for the input. | | `multiple` | bool | - | Indicates whether multiple values can be entered in an input of the type email or file. | | `name` | str | - | Name of the input, used when sending form data. | | `pattern` | str | - | Regex pattern the input's value must match to be valid. | | `placeholder` | str | - | Placeholder text in the input. | | `read_only` | bool | - | Indicates whether the input is read-only. | | `required` | bool | - | Indicates that the input is required. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | Text field size "1" - "3". | | `src` | str | - | URL for image inputs. | | `step` | str, int, float | - | Specifies the legal number intervals for an input. | | `type` | str | - | Specifies the type of input. | | `value` | str, int, float | - | Value of the input. | | `variant` | Literal["classic", "surface", "soft"] | - | Variant of text field: "classic", "surface", "soft". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for text field. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | Override theme radius for text field: "none", "small", "medium", "large", "full". | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_key_down` | Fired when a key is pressed down. | | `on_key_up` | Fired when a key is released. | | `on_change` | Fired when the value of the textarea changes. | ### rx.input.slot Contains icons or buttons associated with an Input. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for text field slot. | | `side` | Literal["left", "right"] | - | Which side of the input the slot should be placed on. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Radio Group Source: http://localhost:3000/docs/library/forms/radio-group.md --- components: - rx.radio_group - rx.radio_group.root - rx.radio_group.item HighLevelRadioGroup: | lambda **props: rx.radio_group(["1", "2", "3", "4", "5"], **props) RadioGroupRoot: | lambda **props: rx.radio_group.root( rx.radio_group.item(value="1"), rx.radio_group.item(value="2"), rx.radio_group.item(value="3"), rx.radio_group.item(value="4"), rx.radio_group.item(value="5"), **props ) RadioGroupItem: | lambda **props: rx.radio_group.root( rx.radio_group.item(value="1", **props), rx.radio_group.item(value="2", **props), rx.radio_group.item(value="3", **props), rx.radio_group.item(value="4", **props), rx.radio_group.item(value="5", **props), default_value="1", ) --- ```python exec import reflex as rx ``` A set of interactive radio buttons where only one can be selected at a time. ## Basic example ```python demo exec class RadioGroupState(rx.State): item: str = "No Selection" @rx.event def set_item(self, item: str): self.item = item def radio_group_state_example(): return rx.vstack( rx.badge(RadioGroupState.item, color_scheme="green"), rx.radio(["1", "2", "3"], on_change=RadioGroupState.set_item, direction="row"), ) ``` ## Submitting a form using Radio Group The `name` prop is used to name the group. It is submitted with its owning form as part of a name/value pair. When the `required` prop is `True`, it indicates that the user must check a radio item before the owning form can be submitted. ```python demo exec class FormRadioState(rx.State): form_data: dict = {} @rx.event def handle_submit(self, form_data: dict): """Handle the form submit.""" self.form_data = form_data def radio_form_example(): return rx.card( rx.vstack( rx.heading("Example Form"), rx.form.root( rx.vstack( rx.radio_group( ["Option 1", "Option 2", "Option 3"], name="radio_choice", direction="row", ), rx.button("Submit", type="submit"), width="100%", spacing="4", ), on_submit=FormRadioState.handle_submit, reset_on_submit=True, ), rx.divider(), rx.hstack( rx.heading("Results:"), rx.badge(FormRadioState.form_data.to_string()), ), align_items="left", width="100%", spacing="4", ), width="50%", ) ``` ## API Reference ### rx.radio_group High level wrapper for the RadioGroup component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `items` | Sequence[str] | - | The items of the radio group. | | `direction` | Literal["row", "column", "row-reverse", "column-reverse"] | - | The direction of the radio group. | | `spacing` | Literal["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] | - | The gap between the items of the radio group. | | `size` | Literal["1", "2", "3"] | - | The size of the radio group. | | `variant` | Literal["classic", "surface", "soft"] | - | The variant of the radio group. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color of the radio group. | | `high_contrast` | bool | - | Whether to render the radio group with higher contrast color against background. | | `value` | str | - | The controlled value of the radio item to check. Should be used in conjunction with on_change. | | `default_value` | str | - | The initial value of checked radio item. Should be used in conjunction with on_change. | | `disabled` | bool | - | Whether the radio group is disabled. | | `name` | str | - | The name of the group. Submitted with its owning form as part of a name/value pair. | | `required` | bool | - | Whether the radio group is required. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.radio_group.root A set of interactive radio buttons where only one can be selected at a time. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the radio group: "1", "2", "3". | | `variant` | Literal["classic", "surface", "soft"] | - | The variant of the radio group. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color of the radio group. | | `high_contrast` | bool | - | Whether to render the radio group with higher contrast color against background. | | `value` | str | - | The controlled value of the radio item to check. Should be used in conjunction with on_change. | | `default_value` | str | - | The initial value of checked radio item. Should be used in conjunction with on_change. | | `disabled` | bool | - | Whether the radio group is disabled. | | `name` | str | - | The name of the group. Submitted with its owning form as part of a name/value pair. | | `required` | bool | - | Whether the radio group is required. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fired when the value of the radio group changes. | ### rx.radio_group.item An item in the group that can be checked. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | str | - | The value of the radio item to check. Should be used in conjunction with on_change. | | `disabled` | bool | - | When true, prevents the user from interacting with the radio item. | | `required` | bool | - | When true, indicates that the user must check the radio item before the owning form can be submitted. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Select Source: http://localhost:3000/docs/library/forms/select.md --- components: - rx.select - rx.select.root - rx.select.trigger - rx.select.content - rx.select.group - rx.select.item - rx.select.label - rx.select.separator HighLevelSelect: | lambda **props: rx.select(["apple", "grape", "pear"], default_value="pear", **props) SelectRoot: | lambda **props: rx.select.root( rx.select.trigger(), rx.select.content( rx.select.group( rx.select.item("apple", value="apple"), rx.select.item("grape", value="grape"), rx.select.item("pear", value="pear"), ), ), default_value="pear", **props ) SelectTrigger: | lambda **props: rx.select.root( rx.select.trigger(**props), rx.select.content( rx.select.group( rx.select.item("apple", value="apple"), rx.select.item("grape", value="grape"), rx.select.item("pear", value="pear"), ), ), default_value="pear", ) SelectContent: | lambda **props: rx.select.root( rx.select.trigger(), rx.select.content( rx.select.group( rx.select.item("apple", value="apple"), rx.select.item("grape", value="grape"), rx.select.item("pear", value="pear"), ), **props, ), default_value="pear", ) SelectItem: | lambda **props: rx.select.root( rx.select.trigger(), rx.select.content( rx.select.group( rx.select.item("apple", value="apple", **props), rx.select.item("grape", value="grape", **props), rx.select.item("pear", value="pear", **props), ), ), default_value="pear", ) --- ```python exec import random import reflex as rx ``` Displays a list of options for the user to pick from—triggered by a button. ```python demo exec class SelectState(rx.State): value: str = "apple" @rx.event def change_value(self, value: str): """Change the select value var.""" self.value = value def select_intro(): return rx.center( rx.select( ["apple", "grape", "pear"], value=SelectState.value, on_change=SelectState.change_value, ), rx.badge(SelectState.value), ) ``` ```python demo exec class SelectState3(rx.State): values: list[str] = ["apple", "grape", "pear"] value: str = "apple" def set_value(self, value: str): self.value = value @rx.event def change_value(self): """Change the select value var.""" self.value = random.choice(self.values) def select_example3(): return rx.vstack( rx.select( SelectState3.values, value=SelectState3.value, on_change=SelectState3.set_value, ), rx.button("Change Value", on_click=SelectState3.change_value), ) ``` The `on_open_change` event handler acts in a similar way to the `on_change` and is called when the open state of the select changes. ```python demo rx.select( ["apple", "grape", "pear"], on_change=rx.window_alert("on_change event handler called"), ) ``` ### Submitting a form using select The `name` prop is needed to submit with its owning form as part of a name/value pair. When the `required` prop is `True`, it indicates that the user must select a value before the owning form can be submitted. ```python demo exec class FormSelectState(rx.State): form_data: dict = {} @rx.event def handle_submit(self, form_data: dict): """Handle the form submit.""" self.form_data = form_data def select_form_example(): return rx.card( rx.vstack( rx.heading("Example Form"), rx.form.root( rx.flex( rx.select( ["apple", "grape", "pear"], default_value="apple", name="select", required=True, ), rx.button("Submit", flex="1", type="submit"), width="100%", spacing="3", ), on_submit=FormSelectState.handle_submit, reset_on_submit=True, ), rx.divider(), rx.hstack( rx.heading("Results:"), rx.badge(FormSelectState.form_data.to_string()), ), align_items="left", width="100%", ), width="50%", ) ``` ### Using Select within a Drawer component If using within a [Drawer](/docs/library/overlay/drawer) component, set the `position` prop to `"popper"` to ensure the select menu is displayed correctly. ```python demo rx.drawer.root( rx.drawer.trigger(rx.button("Open Drawer")), rx.drawer.overlay(z_index="5"), rx.drawer.portal( rx.drawer.content( rx.vstack( rx.drawer.close(rx.box(rx.button("Close"))), rx.select(["apple", "grape", "pear"], position="popper"), ), width="20em", padding="2em", background_color=rx.color("gray", 1), ), ), direction="left", ) ``` ## API Reference ### rx.select High level wrapper for the Select component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the select: "1", "2", "3". | | `default_value` | str | - | The value of the select when initially rendered. Use when you do not need to control the state of the select. | | `value` | str | - | The controlled value of the select. Should be used in conjunction with on_change. | | `default_open` | bool | - | The open state of the select when it is initially rendered. Use when you do not need to control its open state. | | `open` | bool | - | The controlled open state of the select. Must be used in conjunction with on_open_change. | | `name` | str | - | The name of the select control when submitting the form. | | `disabled` | bool | - | When True, prevents the user from interacting with select. | | `required` | bool | - | When True, indicates that the user must select a value before the owning form can be submitted. | | `items` | Sequence[str] | - | The items of the select. | | `placeholder` | str | - | The placeholder of the select. | | `label` | str | - | The label of the select. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color of the select. | | `high_contrast` | bool | - | Whether to render the select with higher contrast color against background. | | `variant` | Literal["classic", "surface", "soft", "ghost"] | - | The variant of the select. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | The radius of the select. | | `width` | str | - | The width of the select. | | `position` | Literal["item-aligned", "popper"] | - | The positioning mode to use. Default is "item-aligned". | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fired when the value of the select changes. | | `on_open_change` | Fired when the select is opened or closed. | ### rx.select.root Displays a list of options for the user to pick from, triggered by a button. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the select: "1", "2", "3". | | `default_value` | str | - | The value of the select when initially rendered. Use when you do not need to control the state of the select. | | `value` | str | - | The controlled value of the select. Should be used in conjunction with on_change. | | `default_open` | bool | - | The open state of the select when it is initially rendered. Use when you do not need to control its open state. | | `open` | bool | - | The controlled open state of the select. Must be used in conjunction with on_open_change. | | `name` | str | - | The name of the select control when submitting the form. | | `disabled` | bool | - | When True, prevents the user from interacting with select. | | `required` | bool | - | When True, indicates that the user must select a value before the owning form can be submitted. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fired when the value of the select changes. | | `on_open_change` | Fired when the select is opened or closed. | ### rx.select.trigger The button that toggles the select. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `variant` | Literal["classic", "surface", "soft", "ghost"] | - | Variant of the select trigger. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color of the select trigger. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | The radius of the select trigger. | | `placeholder` | str | - | The placeholder of the select trigger. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.select.content The component that pops out when the select is open. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `variant` | Literal["solid", "soft"] | - | The variant of the select content. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color of the select content. | | `high_contrast` | bool | - | Whether to render the select content with higher contrast color against background. | | `position` | Literal["item-aligned", "popper"] | - | The positioning mode to use, item-aligned is the default and behaves similarly to a native MacOS menu by positioning content relative to the active item. popper positions content in the same way as our other primitives, for example Popover or DropdownMenu. | | `side` | Literal["top", "right", "bottom", "left"] | - | The preferred side of the anchor to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled. Only available when position is set to popper. | | `side_offset` | int | - | The distance in pixels from the anchor. Only available when position is set to popper. | | `align` | Literal["start", "center", "end"] | - | The preferred alignment against the anchor. May change when collisions occur. Only available when position is set to popper. | | `align_offset` | int | - | The vertical distance in pixels from the anchor. Only available when position is set to popper. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_close_auto_focus` | Fired when the select content is closed. | | `on_escape_key_down` | Fired when the escape key is pressed. | | `on_pointer_down_outside` | Fired when a pointer down event happens outside the select content. | ### rx.select.group Used to group multiple items. #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.select.item The component that contains the select items. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `value` | str | - | The value given as data when submitting a form with a name. | | `disabled` | bool | - | Whether the select item is disabled. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.select.label Used to render the label of a group, it isn't focusable using arrow keys. #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.select.separator Used to visually separate items in the Select. #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Slider Source: http://localhost:3000/docs/library/forms/slider.md --- components: - rx.slider Slider: | lambda **props: rx.center(rx.slider(default_value=40, height="100%", **props), height="4em", width="100%") --- ```python exec import reflex as rx ``` Provides user selection from a range of values. The ## Basic Example The slider can be controlled by a single value or a range of values. Slider can be hooked to state to control its value. Passing a list of two values creates a range slider. ```python demo exec class SliderState(rx.State): value: int = 50 @rx.event def set_end(self, value: list[int | float]): self.value = value[0] def slider_intro(): return rx.vstack( rx.heading(SliderState.value), rx.slider(on_value_commit=SliderState.set_end), width="100%", ) ``` ## Range Slider Range slider is created by passing a list of two values to the `default_value` prop. The list should contain two values that are in the range of the slider. ```python demo exec class RangeSliderState(rx.State): value_start: int = 25 value_end: int = 75 @rx.event def set_end(self, value: list[int | float]): self.value_start = value[0] self.value_end = value[1] def range_slider_intro(): return rx.vstack( rx.hstack( rx.heading(RangeSliderState.value_start), rx.heading(RangeSliderState.value_end), ), rx.slider( default_value=[25, 75], min_=0, max=100, size="1", on_value_commit=RangeSliderState.set_end, ), width="100%", ) ``` ## Live Updating Slider You can use the `on_change` prop to update the slider value as you interact with it. The `on_change` prop takes a function that will be called with the new value of the slider. Here we use the `throttle` method to limit the rate at which the function is called, which is useful to prevent excessive updates. In this example, the slider value is updated every 100ms. ```python demo exec class LiveSliderState(rx.State): value: int = 50 @rx.event def set_end(self, value: list[int | float]): self.value = value[0] def live_slider_intro(): return rx.vstack( rx.heading(LiveSliderState.value), rx.slider( default_value=50, min_=0, max=100, on_change=LiveSliderState.set_end.throttle(100), ), width="100%", ) ``` ## Slider in forms Here we show how to use a slider in a form. We use the `name` prop to identify the slider in the form data. The form data is then passed to the `handle_submit` method to be processed. ```python demo exec class FormSliderState(rx.State): form_data: dict = {} @rx.event def handle_submit(self, form_data: dict): """Handle the form submit.""" self.form_data = form_data def slider_form_example(): return rx.card( rx.vstack( rx.heading("Example Form"), rx.form.root( rx.hstack( rx.slider(default_value=40, name="slider"), rx.button("Submit", type="submit"), width="100%", ), on_submit=FormSliderState.handle_submit, reset_on_submit=True, ), rx.divider(), rx.hstack( rx.heading("Results:"), rx.badge(FormSliderState.form_data.to_string()), ), align_items="left", width="100%", ), width="50%", ) ``` ## API Reference ### rx.slider Provides user selection from a range of values. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child, merging their props and behavior. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | Button size "1" - "3". | | `variant` | Literal["classic", "surface", "soft"] | - | Variant of button. | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for button. | | `high_contrast` | bool | - | Whether to render the button with higher contrast color against background. | | `radius` | Literal["none", "small", "full"] | - | Override theme radius for button: "none", "small", "full". | | `default_value` | Sequence[float, int], float, int | - | The value of the slider when initially rendered. Use when you do not need to control the state of the slider. | | `value` | Sequence[float, int] | - | The controlled value of the slider. Must be used in conjunction with onValueChange. | | `name` | str | - | The name of the slider. Submitted with its owning form as part of a name/value pair. | | `width` | str, NoneType | - | The width of the slider. | | `min` | float, int | - | The minimum value of the slider. | | `max` | float, int | - | The maximum value of the slider. | | `step` | float, int | - | The step value of the slider. | | `disabled` | bool | - | Whether the slider is disabled. | | `orientation` | Literal["vertical", "horizontal"] | - | The orientation of the slider. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fired when the value of the slider changes. | | `on_value_commit` | Fired when a thumb is released after being dragged. | # Switch Source: http://localhost:3000/docs/library/forms/switch.md --- components: - rx.switch Switch: | lambda **props: rx.switch(**props) --- ```python exec import reflex as rx ``` A toggle switch alternative to the checkbox. ## Basic Example Here is a basic example of a switch. We use the `on_change` trigger to toggle the value in the state. ```python demo exec class SwitchState(rx.State): value: bool = False @rx.event def set_end(self, value: bool): self.value = value def switch_intro(): return rx.center( rx.switch(on_change=SwitchState.set_end), rx.badge(SwitchState.value), ) ``` ## Control the value The `checked` prop is used to control the state of the switch. The event `on_change` is called when the state of the switch changes, when the `change_checked` event handler is called. The `disabled` prop when `True`, prevents the user from interacting with the switch. In our example below, even though the second switch is `disabled` we are still able to change whether it is checked or not using the `checked` prop. ```python demo exec class ControlSwitchState(rx.State): checked = True @rx.event def change_checked(self, checked: bool): """Change the switch checked var.""" self.checked = checked def control_switch_example(): return rx.hstack( rx.switch( checked=ControlSwitchState.checked, on_change=ControlSwitchState.change_checked, ), rx.switch( checked=ControlSwitchState.checked, on_change=ControlSwitchState.change_checked, disabled=True, ), ) ``` ## Switch in forms The `name` of the switch is needed to submit with its owning form as part of a name/value pair. When the `required` prop is `True`, it indicates that the user must check the switch before the owning form can be submitted. The `value` prop is only used for form submission, use the `checked` prop to control state of the `switch`. ```python demo exec class FormSwitchState(rx.State): form_data: dict = {} @rx.event def handle_submit(self, form_data: dict): """Handle the form submit.""" self.form_data = form_data def switch_form_example(): return rx.card( rx.vstack( rx.heading("Example Form"), rx.form.root( rx.hstack( rx.switch(name="switch"), rx.button("Submit", type="submit"), width="100%", ), on_submit=FormSwitchState.handle_submit, reset_on_submit=True, ), rx.divider(), rx.hstack( rx.heading("Results:"), rx.badge(FormSwitchState.form_data.to_string()), ), align_items="left", width="100%", ), width="50%", ) ``` ## API Reference ### rx.switch A toggle switch alternative to the checkbox. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `as_child` | bool | - | Change the default rendered element for the one passed as a child, merging their props and behavior. | | `default_checked` | bool | - | Whether the switch is checked by default. | | `checked` | bool | - | Whether the switch is checked. | | `disabled` | bool | - | If true, prevent the user from interacting with the switch. | | `required` | bool | - | If true, the user must interact with the switch to submit the form. | | `name` | str | - | The name of the switch (when submitting a form). | | `value` | str | - | The value associated with the "on" position. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | Switch size "1" - "4". | | `variant` | Literal["classic", "surface", "soft"] | - | Variant of switch: "classic", "surface", "soft". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | Override theme color for switch. | | `high_contrast` | bool | - | Whether to render the switch with higher contrast color against background. | | `radius` | Literal["none", "small", "full"] | - | Override theme radius for switch: "none", "small", "full". | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fired when the value of the switch changes. | # Text Area Source: http://localhost:3000/docs/library/forms/text-area.md --- components: - rx.text_area TextArea: | lambda **props: rx.text_area(**props) --- ```python exec import reflex as rx ``` A text area is a multi-line text input field. ## Basic Example The text area component can be controlled by a single value. The `on_blur` prop can be used to update the value when the text area loses focus. ```python demo exec class TextAreaBlur(rx.State): text: str = "Hello World!" @rx.event def set_text(self, text: str): self.text = text def blur_example(): return rx.vstack( rx.heading(TextAreaBlur.text), rx.text_area( placeholder="Type here...", on_blur=TextAreaBlur.set_text, ), ) ``` ## Text Area in forms Here we show how to use a text area in a form. We use the `name` prop to identify the text area in the form data. The form data is then passed to the `submit_feedback` method to be processed. ```python demo exec class TextAreaFeedbackState(rx.State): feedback: str = "" submitted: bool = False @rx.event def set_feedback(self, value: str): self.feedback = value @rx.event def submit_feedback(self, form_data: dict): self.submitted = True @rx.event def reset_form(self): self.feedback = "" self.submitted = False def feedback_form(): return rx.cond( TextAreaFeedbackState.submitted, rx.card( rx.vstack( rx.text("Thank you for your feedback!"), rx.button( "Submit another response", on_click=TextAreaFeedbackState.reset_form ), ), ), rx.card( rx.form( rx.flex( rx.text("Are you enjoying Reflex?"), rx.text_area( placeholder="Write your feedback…", value=TextAreaFeedbackState.feedback, on_change=TextAreaFeedbackState.set_feedback, resize="vertical", ), rx.button("Send", type="submit"), direction="column", spacing="3", ), on_submit=TextAreaFeedbackState.submit_feedback, ), ), ) ``` ## API Reference ### rx.text_area The input part of a TextArea, may be used by itself. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `access_key` | str | - | Provides a hint for generating a keyboard shortcut for the current element. | | `auto_capitalize` | Literal["off", "none", "on", "sentences", "words", "characters"] | - | Controls whether and how text input is automatically capitalized as it is entered/edited by the user. | | `content_editable` | Literal["inherit", "plaintext-only"], bool | - | Indicates whether the element's content is editable. | | `context_menu` | str | - | Defines the ID of a element which will serve as the element's context menu. | | `dir` | str | - | Defines the text direction. Allowed values are ltr (Left-To-Right) or rtl (Right-To-Left). | | `draggable` | bool | - | Defines whether the element can be dragged. | | `enter_key_hint` | Literal["enter", "done", "go", "next", "previous", "search", "send"] | - | Hints what media types the media element is able to play. | | `hidden` | bool | - | Defines whether the element is hidden. | | `input_mode` | Literal["none", "text", "tel", "url", "email", "numeric", "decimal", "search"] | - | Defines the type of the element. | | `item_prop` | str | - | Defines the name of the element for metadata purposes. | | `lang` | str | - | Defines the language used in the element. | | `role` | Literal["alert", "alertdialog", "application", "article", "banner", "button", "cell", "checkbox", "columnheader", "combobox", "complementary", "contentinfo", "definition", "dialog", "directory", "document", "feed", "figure", "form", "grid", "gridcell", "group", "heading", "img", "link", "list", "listbox", "listitem", "log", "main", "marquee", "math", "menu", "menubar", "menuitem", "menuitemcheckbox", "menuitemradio", "navigation", "none", "note", "option", "presentation", "progressbar", "radio", "radiogroup", "region", "row", "rowgroup", "rowheader", "scrollbar", "search", "searchbox", "separator", "slider", "spinbutton", "status", "switch", "tab", "table", "tablist", "tabpanel", "term", "textbox", "timer", "toolbar", "tooltip", "tree", "treegrid", "treeitem"] | - | Defines the role of the element. | | `slot` | str | - | Assigns a slot in a shadow DOM shadow tree to an element. | | `spell_check` | bool | - | Defines whether the element may be checked for spelling errors. | | `tab_index` | int | - | Defines the position of the current element in the tabbing order. | | `title` | str | - | Defines a tooltip for the element. | | `auto_complete` | bool | - | Whether the form control should have autocomplete enabled. | | `auto_focus` | bool | - | Automatically focuses the textarea when the page loads. | | `auto_height` | bool | - | Automatically fit the content height to the text (use min-height with this prop). | | `cols` | str, int | - | Visible width of the text control, in average character widths. | | `default_value` | str | - | The default value of the textarea when initially rendered. | | `dirname` | str | - | Name part of the textarea to submit in 'dir' and 'name' pair when form is submitted. | | `disabled` | bool | - | Disables the textarea. | | `enter_key_submit` | bool | - | Enter key submits form (shift-enter adds new line). | | `form` | str | - | Associates the textarea with a form (by id). | | `max_length` | int | - | Maximum number of characters allowed in the textarea. | | `min_length` | int | - | Minimum number of characters required in the textarea. | | `name` | str | - | Name of the textarea, used when submitting the form. | | `placeholder` | str | - | Placeholder text in the textarea. | | `read_only` | bool | - | Indicates whether the textarea is read-only. | | `required` | bool | - | Indicates that the textarea is required. | | `rows` | str | - | Visible number of lines in the text control. | | `value` | str | - | The controlled value of the textarea, read only unless used with on_change. | | `wrap` | str | - | How the text in the textarea is to be wrapped when submitting the form. | | `size` | Literal["1", "2", "3"], Breakpoints[str, Literal["1", "2", "3"]] | - | The size of the text area: "1", "2", "3". | | `variant` | Literal["classic", "surface", "soft"] | - | The variant of the text area. | | `resize` | Literal["none", "vertical", "horizontal", "both"], Breakpoints[str, Literal["none", "vertical", "horizontal", "both"]] | - | The resize behavior of the text area: "none", "vertical", "horizontal", "both". | | `color_scheme` | Literal["tomato", "red", "ruby", "crimson", "pink", "plum", "purple", "violet", "iris", "indigo", "blue", "cyan", "teal", "jade", "green", "grass", "brown", "orange", "sky", "mint", "lime", "yellow", "amber", "gold", "bronze", "gray"] | - | The color of the text area. | | `radius` | Literal["none", "small", "medium", "large", "full"] | - | The radius of the text area: "none", "small", "medium", "large", "full". | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | Fired when the input value changes. | | `on_key_down` | Fired when a key is pressed down. | | `on_key_up` | Fired when a key is released. | # File Upload Source: http://localhost:3000/docs/library/forms/upload.md --- components: - rx.upload - rx.upload.root Upload: | lambda **props: rx.center(rx.upload(id="my_upload", **props)) --- ```python exec import reflex as rx ``` Reflex makes it simple to add file upload functionality to your app. You can let users select files, store them on your server, and display or process them as needed. Below is a minimal example that demonstrates how to upload files, save them to disk, and display uploaded images using application state. ## Basic File Upload Example You can let users upload files and keep track of them in your app’s state. The example below allows users to upload files, saves them using the backend, and then displays the uploaded files as images. ```python import reflex as rx class State(rx.State): uploaded_files: list[str] = [] @rx.event async def handle_upload(self, files: list[rx.UploadFile]): for file in files: data = await file.read() path = rx.get_upload_dir() / file.name with path.open("wb") as f: f.write(data) self.uploaded_files.append(file.name) def upload_component(): return rx.vstack( rx.upload(id="upload"), rx.button("Upload", on_click=State.handle_upload(rx.upload_files("upload"))), rx.foreach(State.uploaded_files, lambda f: rx.image(src=rx.get_upload_url(f))), ) ``` ## How File Upload Works Selecting a file will add it to the browser file list, which can be rendered on the frontend using the `rx.selected_files(id)` special Var. To clear the selected files, you can use another special Var `rx.clear_selected_files(id)` as an event handler. To upload the file(s), bind an event handler and pass one of these special event args: - `rx.upload_files(upload_id=id)` for uploads - `rx.upload_files_chunk(upload_id=id)` for larger files that should be processed incrementally ## File Storage Functions Reflex provides two key functions for handling uploaded files: ### rx.get_upload_dir() - **Purpose**: Returns a `Path` object pointing to the server-side directory where uploaded files should be saved - **Usage**: Used in backend event handlers to determine where to save uploaded files - **Default Location**: `./uploaded_files` (can be customized via `REFLEX_UPLOADED_FILES_DIR` environment variable) - **Type**: Returns `pathlib.Path` ### rx.get_upload_url(filename) - **Purpose**: Returns the URL string that can be used in frontend components to access uploaded files - **Usage**: Used in frontend components (like `rx.image`, `rx.video`) to display uploaded files - **URL Format**: `/_upload/filename` - **Type**: Returns `str` ### Key Differences - **rx.get_upload_dir()** -> Backend file path for saving files - **rx.get_upload_url()** -> Frontend URL for displaying files ### Basic Upload Pattern Here is the standard pattern for handling file uploads: ```python import reflex as rx def create_unique_filename(file_name: str): import random import string filename = "".join(random.choices(string.ascii_letters + string.digits, k=10)) return filename + "_" + file_name class State(rx.State): uploaded_files: list[str] = [] @rx.event async def handle_upload(self, files: list[rx.UploadFile]): """Handle file upload with proper directory management.""" for file in files: # Read the file data upload_data = await file.read() # Get the upload directory (backend path) upload_dir = rx.get_upload_dir() # Ensure the directory exists upload_dir.mkdir(parents=True, exist_ok=True) # Create unique filename to prevent conflicts unique_filename = create_unique_filename(file.name) # Create full file path file_path = upload_dir / unique_filename # Save the file with file_path.open("wb") as f: f.write(upload_data) # Store filename for frontend display self.uploaded_files.append(unique_filename) def upload_component(): return rx.vstack( rx.upload( rx.text("Drop files here or click to select"), id="file_upload", border="2px dashed #ccc", padding="2em", ), rx.button( "Upload Files", on_click=State.handle_upload(rx.upload_files(upload_id="file_upload")), ), # Display uploaded files using rx.get_upload_url() rx.foreach( State.uploaded_files, lambda filename: rx.image(src=rx.get_upload_url(filename)), ), ) ``` ### Multiple File Upload Below is an example of how to allow multiple file uploads (in this case images). ```python demo box rx.image(src="https://web.reflex-assets.dev/other/upload.webp") ``` ```python class State(rx.State): """The app state.""" # The images to show. img: list[str] @rx.event async def handle_upload(self, files: list[rx.UploadFile]): """Handle the upload of file(s). Args: files: The uploaded files. """ for file in files: upload_data = await file.read() outfile = rx.get_upload_dir() / file.name # Save the file. with outfile.open("wb") as file_object: file_object.write(upload_data) # Update the img var. self.img.append(file.name) color = "rgb(107,99,246)" def index(): """The main view.""" return rx.vstack( rx.upload( rx.vstack( rx.button( "Select File", color=color, bg="white", border=f"1px solid {color}" ), rx.text("Drag and drop files here or click to select files"), ), id="upload1", border=f"1px dotted {color}", padding="5em", ), rx.hstack(rx.foreach(rx.selected_files("upload1"), rx.text)), rx.button( "Upload", on_click=State.handle_upload(rx.upload_files(upload_id="upload1")), ), rx.button( "Clear", on_click=rx.clear_selected_files("upload1"), ), rx.foreach(State.img, lambda img: rx.image(src=rx.get_upload_url(img))), padding="5em", ) ``` ### Uploading a Single File (Video) Below is an example of how to allow only a single file upload and render (in this case a video). ```python demo box rx.el.video( src="https://web.reflex-assets.dev/other/upload_single_video.webm", auto_play=True, controls=True, loop=True, ) ``` ```python class State(rx.State): """The app state.""" # The video to show. video: str @rx.event async def handle_upload(self, files: list[rx.UploadFile]): """Handle the upload of file(s). Args: files: The uploaded files. """ current_file = files[0] upload_data = await current_file.read() outfile = rx.get_upload_dir() / current_file.name # Save the file. with outfile.open("wb") as file_object: file_object.write(upload_data) # Update the video var. self.video = current_file.name color = "rgb(107,99,246)" def index(): """The main view.""" return rx.vstack( rx.upload( rx.vstack( rx.button( "Select File", color=color, bg="white", border=f"1px solid {color}", ), rx.text("Drag and drop files here or click to select files"), ), id="upload1", max_files=1, border=f"1px dotted {color}", padding="5em", ), rx.text(rx.selected_files("upload1")), rx.button( "Upload", on_click=State.handle_upload(rx.upload_files(upload_id="upload1")), ), rx.button( "Clear", on_click=rx.clear_selected_files("upload1"), ), rx.cond( State.video, rx.video(src=rx.get_upload_url(State.video)), ), padding="5em", ) ``` ### Customizing the Upload In the example below, the upload component accepts a maximum number of 5 files of specific types. It also disables the use of the space or enter key in uploading files. To use a one-step upload, bind the event handler to the `rx.upload` component's `on_drop` trigger. ```python class State(rx.State): """The app state.""" # The images to show. img: list[str] async def handle_upload(self, files: list[rx.UploadFile]): """Handle the upload of file(s). Args: files: The uploaded files. """ for file in files: upload_data = await file.read() outfile = rx.get_upload_dir() / file.name # Save the file. with outfile.open("wb") as file_object: file_object.write(upload_data) # Update the img var. self.img.append(file.name) color = "rgb(107,99,246)" def index(): """The main view.""" return rx.vstack( rx.upload( rx.vstack( rx.button( "Select File", color=color, bg="white", border=f"1px solid {color}" ), rx.text("Drag and drop files here or click to select files"), ), id="upload2", multiple=True, accept={ "application/pdf": [".pdf"], "image/png": [".png"], "image/jpeg": [".jpg", ".jpeg"], "image/gif": [".gif"], "image/webp": [".webp"], "text/html": [".html", ".htm"], }, max_files=5, disabled=False, no_keyboard=True, on_drop=State.handle_upload(rx.upload_files(upload_id="upload2")), border=f"1px dotted {color}", padding="5em", ), rx.grid( rx.foreach( State.img, lambda img: rx.vstack( rx.image(src=rx.get_upload_url(img)), rx.text(img), ), ), columns="2", spacing="1", ), padding="5em", ) ``` ### Unstyled Upload Component To use a completely unstyled upload component and apply your own customization, use `rx.upload.root` instead: ```python demo rx.upload.root( rx.box( rx.icon( tag="cloud_upload", style={ "width": "3rem", "height": "3rem", "color": "#2563eb", "marginBottom": "0.75rem", }, ), rx.hstack( rx.text( "Click to upload", style={"fontWeight": "bold", "color": "#1d4ed8"}, ), " or drag and drop", style={"fontSize": "0.875rem", "color": "#4b5563"}, ), rx.text( "SVG, PNG, JPG or GIF (MAX. 5MB)", style={"fontSize": "0.75rem", "color": "#6b7280", "marginTop": "0.25rem"}, ), style={ "display": "flex", "flexDirection": "column", "alignItems": "center", "justifyContent": "center", "padding": "1.5rem", "textAlign": "center", }, ), id="my_upload", style={ "maxWidth": "24rem", "height": "16rem", "borderWidth": "2px", "borderStyle": "dashed", "borderColor": "#60a5fa", "borderRadius": "0.75rem", "cursor": "pointer", "transitionProperty": "background-color", "transitionDuration": "0.2s", "transitionTimingFunction": "ease-in-out", "display": "flex", "alignItems": "center", "justifyContent": "center", "boxShadow": "0 1px 2px rgba(0, 0, 0, 0.05)", }, ) ``` ## Handling the Upload For uploads, your event handler should be an async function that accepts a single argument, `files: list[UploadFile]`, which will contain [Starlette UploadFile](https://www.starlette.io/requests/#request-files) instances. You can read the files and save them anywhere as shown in the example. In your UI, you can bind the event handler to a trigger, such as a button `on_click` event or upload `on_drop` event, and pass in the files using `rx.upload_files()`. ### Saving the File By convention, Reflex provides the function `rx.get_upload_dir()` to get the directory where uploaded files may be saved. The upload dir comes from the environment variable `REFLEX_UPLOADED_FILES_DIR`, or `./uploaded_files` if not specified. The backend of your app will mount this uploaded files directory on `/_upload` without restriction. Any files uploaded via this mechanism will automatically be publicly accessible. To get the URL for a file inside the upload dir, use the `rx.get_upload_url(filename)` function in a frontend component. ```md alert info # When using the Reflex hosting service, the uploaded files directory is not persistent and will be cleared on every deployment. For persistent storage of uploaded files, it is recommended to use an external service, such as S3. ``` ### Directory Structure and URLs By default, Reflex creates the following structure: ```text your_project/ ├── uploaded_files/ # rx.get_upload_dir() points here │ ├── image1.png │ ├── document.pdf │ └── video.mp4 └── ... ``` The files are automatically served at: - `/_upload/image1.png` ← `rx.get_upload_url("image1.png")` - `/_upload/document.pdf` ← `rx.get_upload_url("document.pdf")` - `/_upload/video.mp4` ← `rx.get_upload_url("video.mp4")` ### Chunked Uploads for Large Files Use `rx.upload_files_chunk(...)` when files may be large or when you want the backend to write data incrementally. Standard uploads spool files to disk before the handler starts, but calling `await file.read()` in the handler loads the entire file into memory at once, which can cause high memory consumption for large files. Chunked upload handlers: - must be declared with `@rx.event(background=True)` - must accept `chunk_iter: rx.UploadChunkIterator` - must fully consume `chunk_iter` To use chunked uploads in your own app: 1. Create an `@rx.event(background=True)` handler. 2. Accept `chunk_iter: rx.UploadChunkIterator`. 3. Iterate over the chunks and write `chunk.data` at `chunk.offset`. 4. Trigger the handler with `rx.upload_files_chunk(upload_id=...)`. Each chunk includes: - `chunk.filename` - `chunk.offset` - `chunk.content_type` - `chunk.data` ```python class ChunkUploadState(rx.State): uploaded_files: list[str] = [] status: str = "No chunked upload has finished yet." @rx.event(background=True) async def handle_large_upload(self, chunk_iter: rx.UploadChunkIterator): file_handles = {} destinations = {} try: async with self: self.status = "Streaming upload in progress." async for chunk in chunk_iter: path = destinations.setdefault( chunk.filename, rx.get_upload_dir() / "stream" / chunk.filename, ) path.parent.mkdir(parents=True, exist_ok=True) fh = file_handles.get(chunk.filename) if fh is None: fh = path.open("wb") file_handles[chunk.filename] = fh fh.seek(chunk.offset) fh.write(chunk.data) finally: for fh in file_handles.values(): fh.close() async with self: self.uploaded_files = sorted(destinations) self.status = "Chunked upload complete." def chunked_upload_component(): return rx.vstack( rx.upload( rx.text("Drop files here or click to select"), id="large_upload", border="2px dashed #ccc", padding="2em", ), rx.button( "Upload Large Files", on_click=ChunkUploadState.handle_large_upload( rx.upload_files_chunk(upload_id="large_upload") ), ), rx.text(ChunkUploadState.status), rx.foreach( ChunkUploadState.uploaded_files, lambda filename: rx.text(filename), ), ) ``` Returning early from the handler will fail the upload because the remaining chunks were not consumed. If you want a progress bar or a cancel button, `rx.upload_files_chunk(...)` supports the same `on_upload_progress` callback as uploads, and you can stop the upload with `rx.cancel_upload(upload_id)`. ## Cancellation The `id` provided to the `rx.upload` component can be passed to the special event handler `rx.cancel_upload(id)` to stop uploading on demand. Cancellation can be triggered directly by a frontend event trigger, or it can be returned from a backend event handler. ## Progress Both `rx.upload_files` and `rx.upload_files_chunk` accept an `on_upload_progress` event trigger which will be fired during the upload operation to report the progress of the upload. This can be used to update a progress bar or other UI elements to show the user the progress of the upload. ```python class UploadExample(rx.State): uploading: bool = False progress: int = 0 total_bytes: int = 0 @rx.event async def handle_upload(self, files: list[rx.UploadFile]): for file in files: self.total_bytes += len(await file.read()) @rx.event def handle_upload_progress(self, progress: dict): self.uploading = True self.progress = round(progress["progress"] * 100) if self.progress >= 100: self.uploading = False @rx.event def cancel_upload(self): self.uploading = False return rx.cancel_upload("upload3") def upload_form(): return rx.vstack( rx.upload( rx.text("Drag and drop files here or click to select files"), id="upload3", border="1px dotted rgb(107,99,246)", padding="5em", ), rx.vstack(rx.foreach(rx.selected_files("upload3"), rx.text)), rx.progress(value=UploadExample.progress, max=100), rx.cond( ~UploadExample.uploading, rx.button( "Upload", on_click=UploadExample.handle_upload( rx.upload_files( upload_id="upload3", on_upload_progress=UploadExample.handle_upload_progress, ), ), ), rx.button("Cancel", on_click=UploadExample.cancel_upload), ), rx.text("Total bytes uploaded: ", UploadExample.total_bytes), align="center", ) ``` The `progress` dictionary contains the following keys: ```python { "loaded": 36044800, "total": 54361908, "progress": 0.6630525183185255, } ``` ## API Reference ### rx.upload The styled Upload Component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `accept` | dict[str, Sequence], NoneType | - | The list of accepted file types. This should be a dictionary of MIME types as keys and array of file formats as values. supported MIME types: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types. | | `disabled` | bool | - | Whether the dropzone is disabled. | | `max_files` | int | - | The maximum number of files that can be uploaded. | | `max_size` | int | - | The maximum file size (bytes) that can be uploaded. | | `min_size` | int | - | The minimum file size (bytes) that can be uploaded. | | `multiple` | bool | - | Whether to allow multiple files to be uploaded. | | `no_click` | bool | - | Whether to disable click to upload. | | `no_drag` | bool | - | Whether to disable drag and drop. | | `no_keyboard` | bool | - | Whether to disable using the space/enter keys to upload. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_drop` | | | `on_drop_rejected` | Fired when dropped files do not meet the specified criteria. | ### rx.upload.root A file upload component. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `accept` | dict[str, Sequence], NoneType | - | The list of accepted file types. This should be a dictionary of MIME types as keys and array of file formats as values. supported MIME types: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types. | | `disabled` | bool | - | Whether the dropzone is disabled. | | `max_files` | int | - | The maximum number of files that can be uploaded. | | `max_size` | int | - | The maximum file size (bytes) that can be uploaded. | | `min_size` | int | - | The minimum file size (bytes) that can be uploaded. | | `multiple` | bool | - | Whether to allow multiple files to be uploaded. | | `no_click` | bool | - | Whether to disable click to upload. | | `no_drag` | bool | - | Whether to disable drag and drop. | | `no_keyboard` | bool | - | Whether to disable using the space/enter keys to upload. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_drop` | | | `on_drop_rejected` | Fired when dropped files do not meet the specified criteria. | # Area Chart Source: http://localhost:3000/docs/library/graphing/charts/areachart.md --- components: - rx.recharts.AreaChart - rx.recharts.Area --- ```python exec import reflex as rx import random ``` A Recharts area chart displays quantitative data using filled areas between a line connecting data points and the axis. ## Basic Example ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def area_simple(): return rx.recharts.area_chart( rx.recharts.area( data_key="uv", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, width="100%", height=250, ) ``` ## Syncing Charts The `sync_id` prop allows you to sync two graphs. In the example, it is set to "1" for both charts, indicating that they should be synchronized. This means that any interactions (such as brushing) performed on one chart will be reflected in the other chart. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def area_sync(): return rx.vstack( rx.recharts.bar_chart( rx.recharts.graphing_tooltip(), rx.recharts.bar(data_key="uv", stroke="#8884d8", fill="#8884d8"), rx.recharts.bar( data_key="pv", stroke="#82ca9d", fill="#82ca9d", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, sync_id="1", width="100%", height=200, ), rx.recharts.composed_chart( rx.recharts.area(data_key="uv", stroke="#8884d8", fill="#8884d8"), rx.recharts.line( data_key="pv", type_="monotone", stroke="#ff7300", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), rx.recharts.graphing_tooltip(), rx.recharts.brush(data_key="name", height=30, stroke="#8884d8"), data=data, sync_id="1", width="100%", height=250, ), width="100%", ) ``` ## Stacking Charts The `stack_id` prop allows you to stack multiple graphs on top of each other. In the example, it is set to "1" for both charts, indicating that they should be stacked together. This means that the bars or areas of the charts will be vertically stacked, with the values of each chart contributing to the total height of the stacked areas or bars. This is similar to the `sync_id` prop, but instead of synchronizing the interaction between the charts, it just stacks the charts on top of each other. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def area_stack(): return rx.recharts.area_chart( rx.recharts.area( data_key="uv", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), stack_id="1", ), rx.recharts.area( data_key="pv", stroke=rx.color("green", 9), fill=rx.color("green", 8), stack_id="1", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, stack_offset="none", margin={"top": 5, "right": 5, "bottom": 5, "left": 5}, width="100%", height=300, ) ``` ## Multiple Axis Multiple axes can be used for displaying different data series with varying scales or units on the same chart. This allows for a more comprehensive comparison and analysis of the data. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def area_multi_axis(): return rx.recharts.area_chart( rx.recharts.area( data_key="uv", stroke="#8884d8", fill="#8884d8", x_axis_id="primary", y_axis_id="left", ), rx.recharts.area( data_key="pv", x_axis_id="secondary", y_axis_id="right", type_="monotone", stroke="#82ca9d", fill="#82ca9d", ), rx.recharts.x_axis(data_key="name", x_axis_id="primary"), rx.recharts.x_axis(data_key="name", x_axis_id="secondary", orientation="top"), rx.recharts.y_axis(data_key="uv", y_axis_id="left"), rx.recharts.y_axis(data_key="pv", y_axis_id="right", orientation="right"), rx.recharts.graphing_tooltip(), rx.recharts.legend(), data=data, width="100%", height=300, ) ``` ## Layout Use the `layout` prop to set the orientation to either `"horizontal"` (default) or `"vertical"`. ```md alert info # Include margins around your graph to ensure proper spacing and enhance readability. By default, provide margins on all sides of the chart to create a visually appealing and functional representation of your data. ``` ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def area_vertical(): return rx.recharts.area_chart( rx.recharts.area( data_key="uv", stroke=rx.color("accent", 8), fill=rx.color("accent", 3), ), rx.recharts.x_axis(type_="number"), rx.recharts.y_axis(data_key="name", type_="category"), data=data, layout="vertical", height=300, width="100%", ) ``` ## Stateful Example Here is an example of an area graph with a `State`. Here we have defined a function `randomize_data`, which randomly changes the data for both graphs when the first defined `area` is clicked on using `on_click=AreaState.randomize_data`. ```python demo exec class AreaState(rx.State): data = data curve_type = "" @rx.event def randomize_data(self): for i in range(len(self.data)): self.data[i]["uv"] = random.randint(0, 10000) self.data[i]["pv"] = random.randint(0, 10000) self.data[i]["amt"] = random.randint(0, 10000) def change_curve_type(self, type_input): self.curve_type = type_input def area_stateful(): return rx.vstack( rx.hstack( rx.text("Curve Type:"), rx.select( ["basis", "natural", "step"], on_change=AreaState.change_curve_type, default_value="basis", ), ), rx.recharts.area_chart( rx.recharts.area( data_key="uv", on_click=AreaState.randomize_data, type_=AreaState.curve_type, ), rx.recharts.area( data_key="pv", stroke="#82ca9d", fill="#82ca9d", on_click=AreaState.randomize_data, type_=AreaState.curve_type, ), rx.recharts.x_axis( data_key="name", ), rx.recharts.y_axis(), rx.recharts.legend(), rx.recharts.cartesian_grid(), data=AreaState.data, width="100%", height=400, ), width="100%", ) ``` ## API Reference ### rx.recharts.AreaChart An Area chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `data` | Sequence[dict[str, Any]] | - | The source data, in which each element is an object. | | `margin` | dict[str, Any] | - | The sizes of whitespace around the chart, i.e. {"top": 50, "right": 30, "left": 20, "bottom": 5}. | | `sync_id` | str | - | If any two categorical charts(rx.line_chart, rx.area_chart, rx.bar_chart, rx.composed_chart) have the same sync_id, these two charts can sync the position GraphingTooltip, and the start_index, end_index of Brush. | | `sync_method` | Literal["index", "value"] | `"index"` | When sync_id is provided, allows customisation of how the charts will synchronize GraphingTooltips and brushes. Using 'index' (default setting), other charts will reuse current datum's index within the data array. In cases where data does not have the same length, this might yield unexpected results. In that case use 'value' which will try to match other charts values, or a fully custom function which will receive tick, data as argument and should return an index. 'index', 'value', function. | | `layout` | Literal["vertical", "horizontal"] | `"horizontal"` | The layout of area in the chart. 'horizontal', 'vertical'. | | `stack_offset` | Literal["expand", "none", "wiggle", "silhouette"] | - | The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand', 'none', 'wiggle', 'silhouette'. | | `base_value` | int, Literal["dataMin", "dataMax", "auto"] | `"auto"` | The base value of area. Number, 'dataMin', 'dataMax', 'auto'. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.Area An Area component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `layout` | Literal["vertical", "horizontal"] | - | The layout of bar in the chart, usually inherited from parent. 'horizontal', 'vertical'. | | `data_key` | str, int | - | The key of a group of data which should be unique in an area chart. | | `x_axis_id` | str, int | `0` | The id of x-axis which is corresponding to the data. | | `y_axis_id` | str, int | `0` | The id of y-axis which is corresponding to the data. | | `legend_type` | Literal["circle", "cross", "diamond", "line", "plainline", "rect", "square", "star", "triangle", "wye", "none"] | - | The type of icon in legend. If set to 'none', no legend item will be rendered. 'line', 'plainline', 'square', 'rect'\| 'circle', 'cross', 'diamond', 'star', 'triangle', 'wye', 'none' optional. | | `label` | dict[str, Any], bool | `False` | If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. | | `is_animation_active` | bool | `True` | If set false, animation of bar will be disabled. | | `animation_begin` | int | `0` | Specifies when the animation should begin, the unit of this option is ms. | | `animation_duration` | int | `1500` | Specifies the duration of animation, the unit of this option is ms. | | `animation_easing` | Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] | `"ease"` | The type of easing function. | | `unit` | str, int | - | The unit of data. This option will be used in tooltip. | | `name` | str, int | - | The name of data. This option will be used in tooltip and legend to represent the component. If no value was set to this option, the value of dataKey will be used alternatively. | | `stroke` | str, Color | `rx.color("accent", 9)` | The color of the line stroke. | | `stroke_width` | str, int, float | `1` | The width of the line stroke. | | `fill` | str, Color | `rx.color("accent", 5)` | The color of the area fill. | | `type_` | Literal["basis", "basisClosed", "basisOpen", "bumpX", "bumpY", "bump", "linear", "linearClosed", "natural", "monotoneX", "monotoneY", "monotone", "step", "stepBefore", "stepAfter"] | `"monotone"` | The interpolation type of area. And customized interpolation function can be set to type. 'basis', 'basisClosed', 'basisOpen', 'bumpX', 'bumpY', 'bump', 'linear', 'linearClosed', 'natural', 'monotoneX', 'monotoneY', 'monotone', 'step', 'stepBefore', 'stepAfter'. | | `dot` | dict[str, Any], bool | `False` | If false set, dots will not be drawn. If true set, dots will be drawn which have the props calculated internally. | | `active_dot` | dict[str, Any], bool | `{stroke: rx.color("accent", 2), fill: rx.color("accent", 10)}` | The dot is shown when user enter an area chart and this chart has tooltip. If false set, no active dot will not be drawn. If true set, active dot will be drawn which have the props calculated internally. | | `base_line` | int, Sequence[dict[str, Any]] | - | The value which can describle the line, usually calculated internally. | | `points` | Sequence[dict[str, Any]] | - | The coordinates of all the points in the area, usually calculated internally. | | `stack_id` | str, int | - | The stack id of area, when two areas have the same value axis and same stack_id, then the two areas are stacked in order. | | `connect_nulls` | bool | `False` | Whether to connect a graph area across null points. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_animation_start` | The customized event handler of animation start. | | `on_animation_end` | The customized event handler of animation end. | # Bar Chart Source: http://localhost:3000/docs/library/graphing/charts/barchart.md --- components: - rx.recharts.BarChart - rx.recharts.Bar --- ```python exec import reflex as rx import random ``` A bar chart presents categorical data with rectangular bars with heights or lengths proportional to the values that they represent. For a bar chart we must define an `rx.recharts.bar()` component for each set of values we wish to plot. Each `rx.recharts.bar()` component has a `data_key` which clearly states which variable in our data we are tracking. In this simple example we plot `uv` as a bar against the `name` column which we set as the `data_key` in `rx.recharts.x_axis`. ## Simple Example ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def bar_simple(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="uv", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, width="100%", height=250, ) ``` ## Multiple Bars Multiple bars can be placed on the same `bar_chart`, using multiple `rx.recharts.bar()` components. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def bar_double(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="uv", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.bar( data_key="pv", stroke=rx.color("green", 9), fill=rx.color("green", 8), ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, width="100%", height=250, ) ``` ## Ranged Charts You can also assign a range in the bar by assigning the data_key in the `rx.recharts.bar` to a list with two elements, i.e. here a range of two temperatures for each date. ```python demo graphing range_data = [ {"day": "05-01", "temperature": [-1, 10]}, {"day": "05-02", "temperature": [2, 15]}, {"day": "05-03", "temperature": [3, 12]}, {"day": "05-04", "temperature": [4, 12]}, {"day": "05-05", "temperature": [12, 16]}, {"day": "05-06", "temperature": [5, 16]}, {"day": "05-07", "temperature": [3, 12]}, {"day": "05-08", "temperature": [0, 8]}, {"day": "05-09", "temperature": [-3, 5]}, ] def bar_range(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="temperature", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.x_axis(data_key="day"), rx.recharts.y_axis(), data=range_data, width="100%", height=250, ) ``` ## Stateful Charts Here is an example of a bar graph with a `State`. Here we have defined a function `randomize_data`, which randomly changes the data for both graphs when the first defined `bar` is clicked on using `on_click=BarState.randomize_data`. ```python demo exec class BarState(rx.State): data = data @rx.event def randomize_data(self): for i in range(len(self.data)): self.data[i]["uv"] = random.randint(0, 10000) self.data[i]["pv"] = random.randint(0, 10000) self.data[i]["amt"] = random.randint(0, 10000) def bar_with_state(): return rx.recharts.bar_chart( rx.recharts.cartesian_grid( stroke_dasharray="3 3", ), rx.recharts.bar( data_key="uv", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.bar( data_key="pv", stroke=rx.color("green", 9), fill=rx.color("green", 8), ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), rx.recharts.legend(), on_click=BarState.randomize_data, data=BarState.data, width="100%", height=300, ) ``` ## Example with Props Here's an example demonstrates how to customize the appearance and layout of bars using the `bar_category_gap`, `bar_gap`, `bar_size`, and `max_bar_size` props. These props accept values in pixels to control the spacing and size of the bars. ```python demo graphing data = [ {"name": "Page A", "value": 2400}, {"name": "Page B", "value": 1398}, {"name": "Page C", "value": 9800}, {"name": "Page D", "value": 3908}, {"name": "Page E", "value": 4800}, {"name": "Page F", "value": 3800}, ] def bar_features(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="value", fill=rx.color("accent", 8), ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, bar_category_gap="15%", bar_gap=6, bar_size=100, max_bar_size=40, width="100%", height=300, ) ``` ## Vertical Example The `layout` prop allows you to set the orientation of the graph to be vertical or horizontal, it is set horizontally by default. ```md alert info # Include margins around your graph to ensure proper spacing and enhance readability. By default, provide margins on all sides of the chart to create a visually appealing and functional representation of your data. ``` ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def bar_vertical(): return rx.recharts.bar_chart( rx.recharts.bar( data_key="uv", stroke=rx.color("accent", 8), fill=rx.color("accent", 3), ), rx.recharts.x_axis(type_="number"), rx.recharts.y_axis(data_key="name", type_="category"), data=data, layout="vertical", margin={"top": 20, "right": 20, "left": 20, "bottom": 20}, width="100%", height=300, ) ``` To learn how to use the `sync_id`, `stack_id`,`x_axis_id` and `y_axis_id` props check out the of the area chart [documentation](/docs/library/graphing/charts/areachart), where these props are all described with examples. ## API Reference ### rx.recharts.BarChart A Bar chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `data` | Sequence[dict[str, Any]] | - | The source data, in which each element is an object. | | `margin` | dict[str, Any] | - | The sizes of whitespace around the chart, i.e. {"top": 50, "right": 30, "left": 20, "bottom": 5}. | | `sync_id` | str | - | If any two categorical charts(rx.line_chart, rx.area_chart, rx.bar_chart, rx.composed_chart) have the same sync_id, these two charts can sync the position GraphingTooltip, and the start_index, end_index of Brush. | | `sync_method` | Literal["index", "value"] | `"index"` | When sync_id is provided, allows customisation of how the charts will synchronize GraphingTooltips and brushes. Using 'index' (default setting), other charts will reuse current datum's index within the data array. In cases where data does not have the same length, this might yield unexpected results. In that case use 'value' which will try to match other charts values, or a fully custom function which will receive tick, data as argument and should return an index. 'index', 'value', function. | | `layout` | Literal["vertical", "horizontal"] | `"horizontal"` | The layout of area in the chart. 'horizontal', 'vertical'. | | `stack_offset` | Literal["expand", "none", "wiggle", "silhouette"] | `"none"` | The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. | | `bar_category_gap` | str, int | `"10%"` | The gap between two bar categories, which can be a percent value or a fixed value. Percentage, Number. | | `bar_gap` | str, int | `4` | The gap between two bars in the same category, which can be a percent value or a fixed value. Percentage, Number. | | `bar_size` | int | - | The width of all the bars in the chart. Number. | | `max_bar_size` | int | - | The maximum width of all the bars in a horizontal BarChart, or maximum height in a vertical BarChart. | | `reverse_stack_order` | bool | `False` | If false set, stacked items will be rendered left to right. If true set, stacked items will be rendered right to left. (Render direction affects SVG layering, not x position.). | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.Bar A Bar component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `layout` | Literal["vertical", "horizontal"] | - | The layout of bar in the chart, usually inherited from parent. 'horizontal', 'vertical'. | | `data_key` | str, int | - | The key of a group of data which should be unique in an area chart. | | `x_axis_id` | str, int | `0` | The id of x-axis which is corresponding to the data. | | `y_axis_id` | str, int | `0` | The id of y-axis which is corresponding to the data. | | `legend_type` | Literal["circle", "cross", "diamond", "line", "plainline", "rect", "square", "star", "triangle", "wye", "none"] | - | The type of icon in legend. If set to 'none', no legend item will be rendered. 'line', 'plainline', 'square', 'rect'\| 'circle', 'cross', 'diamond', 'star', 'triangle', 'wye', 'none' optional. | | `label` | dict[str, Any], bool | `False` | If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. | | `is_animation_active` | bool | `True` | If set false, animation of bar will be disabled. | | `animation_begin` | int | `0` | Specifies when the animation should begin, the unit of this option is ms. | | `animation_duration` | int | `1500` | Specifies the duration of animation, the unit of this option is ms. | | `animation_easing` | Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] | `"ease"` | The type of easing function. | | `unit` | str, int | - | The unit of data. This option will be used in tooltip. | | `name` | str, int | - | The name of data. This option will be used in tooltip and legend to represent a bar. If no value was set to this option, the value of dataKey will be used alternatively. | | `stroke` | str, Color | - | The color of the line stroke. | | `stroke_width` | str, int, float | - | The width of the line stroke. | | `fill` | str, Color | `Color("accent", 9)` | The width of the line stroke. | | `background` | bool | `False` | If false set, background of bars will not be drawn. If true set, background of bars will be drawn which have the props calculated internally. | | `stack_id` | str | - | The stack id of bar, when two bars have the same value axis and same stack_id, then the two bars are stacked in order. | | `min_point_size` | int | - | The minimal height of a bar in a horizontal BarChart, or the minimal width of a bar in a vertical BarChart. By default, 0 values are not shown. To visualize a 0 (or close to zero) point, set the minimal point size to a pixel value like 3. In stacked bar charts, minPointSize might not be respected for tightly packed values. So we strongly recommend not using this prop in stacked BarCharts. | | `bar_size` | int | - | Size of the bar (if one bar_size is set then a bar_size must be set for all bars). | | `max_bar_size` | int | - | Max size of the bar. | | `radius` | int, Sequence[int] | `0` | If set a value, the option is the radius of all the rounded corners. If set a array, the option are in turn the radiuses of top-left corner, top-right corner, bottom-right corner, bottom-left corner. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_animation_start` | The customized event handler of animation start. | | `on_animation_end` | The customized event handler of animation end. | # Composed Chart Source: http://localhost:3000/docs/library/graphing/charts/composedchart.md --- components: - rx.recharts.ComposedChart --- ```python exec import reflex as rx ``` A `composed_chart` is a higher-level component chart that is composed of multiple charts, where other charts are the children of the `composed_chart`. The charts are placed on top of each other in the order they are provided in the `composed_chart` function. ```md alert info # To learn more about individual charts, checkout: **[area_chart](/docs/library/graphing/charts/areachart)**, **[line_chart](/docs/library/graphing/charts/linechart)**, or **[bar_chart](/docs/library/graphing/charts/barchart)**. ``` ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def composed(): return rx.recharts.composed_chart( rx.recharts.area(data_key="uv", stroke="#8884d8", fill="#8884d8"), rx.recharts.bar(data_key="amt", bar_size=20, fill="#413ea0"), rx.recharts.line(data_key="pv", type_="monotone", stroke="#ff7300"), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), rx.recharts.cartesian_grid(stroke_dasharray="3 3"), rx.recharts.graphing_tooltip(), data=data, height=250, width="100%", ) ``` ## API Reference ### rx.recharts.ComposedChart A Composed chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `data` | Sequence[dict[str, Any]] | - | The source data, in which each element is an object. | | `margin` | dict[str, Any] | - | The sizes of whitespace around the chart, i.e. {"top": 50, "right": 30, "left": 20, "bottom": 5}. | | `sync_id` | str | - | If any two categorical charts(rx.line_chart, rx.area_chart, rx.bar_chart, rx.composed_chart) have the same sync_id, these two charts can sync the position GraphingTooltip, and the start_index, end_index of Brush. | | `sync_method` | Literal["index", "value"] | `"index"` | When sync_id is provided, allows customisation of how the charts will synchronize GraphingTooltips and brushes. Using 'index' (default setting), other charts will reuse current datum's index within the data array. In cases where data does not have the same length, this might yield unexpected results. In that case use 'value' which will try to match other charts values, or a fully custom function which will receive tick, data as argument and should return an index. 'index', 'value', function. | | `layout` | Literal["vertical", "horizontal"] | `"horizontal"` | The layout of area in the chart. 'horizontal', 'vertical'. | | `stack_offset` | Literal["expand", "none", "wiggle", "silhouette"] | - | The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand', 'none', 'wiggle', 'silhouette'. | | `base_value` | int, Literal["dataMin", "dataMax", "auto"] | `"auto"` | The base value of area. Number, 'dataMin', 'dataMax', 'auto'. | | `bar_category_gap` | str, int | `"10%"` | The gap between two bar categories, which can be a percent value or a fixed value. Percentage, Number. | | `bar_gap` | int | `4` | The gap between two bars in the same category. | | `bar_size` | int | - | The width or height of each bar. If the barSize is not specified, the size of the bar will be calculated by the barCategoryGap, barGap and the quantity of bar groups. | | `reverse_stack_order` | bool | `False` | If false set, stacked items will be rendered left to right. If true set, stacked items will be rendered right to left. (Render direction affects SVG layering, not x position). | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Error Bar Source: http://localhost:3000/docs/library/graphing/charts/errorbar.md --- components: - rx.recharts.ErrorBar --- ```python exec import reflex as rx ``` An error bar is a graphical representation of the uncertainty or variability of a data point in a chart, depicted as a line extending from the data point parallel to one of the axes. The `data_key`, `width`, `stroke_width`, `stroke`, and `direction` props can be used to customize the appearance and behavior of the error bars, specifying the data source, dimensions, color, and orientation of the error bars. ```python demo graphing data = [ {"x": 45, "y": 100, "z": 150, "errorY": [30, 20], "errorX": 5}, {"x": 100, "y": 200, "z": 200, "errorY": [20, 30], "errorX": 3}, {"x": 120, "y": 100, "z": 260, "errorY": 20, "errorX": [5, 3]}, {"x": 170, "y": 300, "z": 400, "errorY": [15, 18], "errorX": 4}, {"x": 140, "y": 250, "z": 280, "errorY": 23, "errorX": [6, 7]}, {"x": 150, "y": 400, "z": 500, "errorY": [21, 10], "errorX": 4}, {"x": 110, "y": 280, "z": 200, "errorY": 21, "errorX": [5, 6]}, ] def error(): return rx.recharts.scatter_chart( rx.recharts.scatter( rx.recharts.error_bar( data_key="errorY", direction="y", width=4, stroke_width=2, stroke="red" ), rx.recharts.error_bar( data_key="errorX", direction="x", width=4, stroke_width=2 ), data=data, fill="#8884d8", name="A", ), rx.recharts.x_axis(data_key="x", name="x", type_="number"), rx.recharts.y_axis(data_key="y", name="y", type_="number"), width="100%", height=300, ) ``` ## API Reference ### rx.recharts.ErrorBar An ErrorBar component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `direction` | Literal["x", "y"] | - | Only used for ScatterChart with error bars in two directions. Only accepts a value of "x" or "y" and makes the error bars lie in that direction. | | `data_key` | str, int | - | The key of a group of data which should be unique in an area chart. | | `width` | int | `5` | The width of the error bar ends. | | `stroke` | str, Color | `rx.color("gray", 8)` | The stroke color of error bar. | | `stroke_width` | str, int, float | `1.5` | The stroke width of error bar. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Funnel Chart Source: http://localhost:3000/docs/library/graphing/charts/funnelchart.md --- components: - rx.recharts.FunnelChart - rx.recharts.Funnel --- ```python exec import reflex as rx import random rx.toast.provider() ``` A funnel chart is a graphical representation used to visualize how data moves through a process. In a funnel chart, the dependent variable’s value diminishes in the subsequent stages of the process. It can be used to demonstrate the flow of users through a business or sales process. ## Simple Example ```python demo graphing data = [ {"value": 100, "name": "Sent", "fill": "#8884d8"}, {"value": 80, "name": "Viewed", "fill": "#83a6ed"}, {"value": 50, "name": "Clicked", "fill": "#8dd1e1"}, {"value": 40, "name": "Add to Cart", "fill": "#82ca9d"}, {"value": 26, "name": "Purchased", "fill": "#a4de6c"}, ] def funnel_simple(): return rx.recharts.funnel_chart( rx.recharts.funnel( rx.recharts.label_list( position="right", data_key="name", fill="#000", stroke="none", ), data_key="value", data=data, ), width="100%", height=250, ) ``` ## Event Triggers Funnel chart supports `on_click`, `on_mouse_enter`, `on_mouse_leave` and `on_mouse_move` event triggers, allows you to interact with the funnel chart and perform specific actions based on user interactions. ```python demo graphing data = [ {"value": 100, "name": "Sent", "fill": "#8884d8"}, {"value": 80, "name": "Viewed", "fill": "#83a6ed"}, {"value": 50, "name": "Clicked", "fill": "#8dd1e1"}, {"value": 40, "name": "Add to Cart", "fill": "#82ca9d"}, {"value": 26, "name": "Purchased", "fill": "#a4de6c"}, ] def funnel_events(): return rx.recharts.funnel_chart( rx.recharts.funnel( rx.recharts.label_list( position="right", data_key="name", fill="#000", stroke="none", ), data_key="value", data=data, ), on_click=rx.toast("Clicked on funnel chart"), on_mouse_enter=rx.toast("Mouse entered"), on_mouse_leave=rx.toast("Mouse left"), width="100%", height=250, ) ``` ## Dynamic Data Here is an example of a funnel chart with a `State`. Here we have defined a function `randomize_data`, which randomly changes the data when the graph is clicked on using `on_click=FunnelState.randomize_data`. ```python exec data = [ {"value": 100, "name": "Sent", "fill": "#8884d8"}, {"value": 80, "name": "Viewed", "fill": "#83a6ed"}, {"value": 50, "name": "Clicked", "fill": "#8dd1e1"}, {"value": 40, "name": "Add to Cart", "fill": "#82ca9d"}, {"value": 26, "name": "Purchased", "fill": "#a4de6c"}, ] ``` ```python demo exec class FunnelState(rx.State): data = data @rx.event def randomize_data(self): self.data[0]["value"] = 100 for i in range(len(self.data) - 1): self.data[i + 1]["value"] = self.data[i]["value"] - random.randint(0, 20) def funnel_state(): return rx.recharts.funnel_chart( rx.recharts.funnel( rx.recharts.label_list( position="right", data_key="name", fill="#000", stroke="none", ), data_key="value", data=FunnelState.data, on_click=FunnelState.randomize_data, ), rx.recharts.graphing_tooltip(), width="100%", height=250, ) ``` ## Changing the Chart Animation The `is_animation_active` prop can be used to turn off the animation, but defaults to `True`. `animation_begin` sets the delay before animation starts, `animation_duration` determines how long the animation lasts, and `animation_easing` defines the speed curve of the animation for smooth transitions. ```python demo graphing data = [ {"name": "Visits", "value": 5000, "fill": "#8884d8"}, {"name": "Cart", "value": 3000, "fill": "#83a6ed"}, {"name": "Checkout", "value": 2500, "fill": "#8dd1e1"}, {"name": "Purchase", "value": 1000, "fill": "#82ca9d"}, ] def funnel_animation(): return rx.recharts.funnel_chart( rx.recharts.funnel( data_key="value", data=data, animation_begin=300, animation_duration=9000, animation_easing="ease-in-out", ), rx.recharts.graphing_tooltip(), rx.recharts.legend(), width="100%", height=300, ) ``` ## API Reference ### rx.recharts.FunnelChart A Funnel chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `layout` | str | `"centric"` | The layout of bars in the chart. | | `margin` | dict[str, Any] | `{"top": 5, "right": 5, "bottom": 5, "left": 5}` | The sizes of whitespace around the chart. | | `stroke` | str, Color | - | The stroke color of each bar. String, Object. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.Funnel A Funnel component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `data` | Sequence[dict[str, Any]] | - | The source data, in which each element is an object. | | `data_key` | str, int | - | The key or getter of a group of data which should be unique in a FunnelChart. | | `name_key` | str | `"name"` | The key of each sector's name. | | `legend_type` | Literal["circle", "cross", "diamond", "line", "plainline", "rect", "square", "star", "triangle", "wye", "none"] | `"line"` | The type of icon in legend. If set to 'none', no legend item will be rendered. | | `is_animation_active` | bool | `True` | If set false, animation of line will be disabled. | | `animation_begin` | int | `0` | Specifies when the animation should begin, the unit of this option is ms. | | `animation_duration` | int | `1500` | Specifies the duration of animation, the unit of this option is ms. | | `animation_easing` | Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] | - | The type of easing function. 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear'. Default "ease". | | `stroke` | str, Color | `rx.color("gray", 3)` | Stroke color. | | `trapezoids` | Sequence[dict[str, Any]] | - | The coordinates of all the trapezoids in the funnel, usually calculated internally. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_animation_start` | The customized event handler of animation start. | | `on_animation_end` | The customized event handler of animation end. | # Line Chart Source: http://localhost:3000/docs/library/graphing/charts/linechart.md --- components: - rx.recharts.LineChart - rx.recharts.Line --- ```python exec import random from typing import Any import reflex as rx ``` A line chart is a type of chart used to show information that changes over time. Line charts are created by plotting a series of several points and connecting them with a straight line. ## Simple Example For a line chart we must define an `rx.recharts.line()` component for each set of values we wish to plot. Each `rx.recharts.line()` component has a `data_key` which clearly states which variable in our data we are tracking. In this simple example we plot `pv` and `uv` as separate lines against the `name` column which we set as the `data_key` in `rx.recharts.x_axis`. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def line_simple(): return rx.recharts.line_chart( rx.recharts.line( data_key="pv", ), rx.recharts.line( data_key="uv", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, width="100%", height=300, ) ``` ## Example with Props Our second example uses exactly the same data as our first example, except now we add some extra features to our line graphs. We add a `type_` prop to `rx.recharts.line` to style the lines differently. In addition, we add an `rx.recharts.cartesian_grid` to get a grid in the background, an `rx.recharts.legend` to give us a legend for our graphs and an `rx.recharts.graphing_tooltip` to add a box with text that appears when you pause the mouse pointer on an element in the graph. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def line_features(): return rx.recharts.line_chart( rx.recharts.line( data_key="pv", type_="monotone", stroke="#8884d8", ), rx.recharts.line( data_key="uv", type_="monotone", stroke="#82ca9d", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), rx.recharts.cartesian_grid(stroke_dasharray="3 3"), rx.recharts.graphing_tooltip(), rx.recharts.legend(), data=data, width="100%", height=300, ) ``` ## Layout The `layout` prop allows you to set the orientation of the graph to be vertical or horizontal. The `margin` prop defines the spacing around the graph, ```md alert info # Include margins around your graph to ensure proper spacing and enhance readability. By default, provide margins on all sides of the chart to create a visually appealing and functional representation of your data. ``` ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def line_vertical(): return rx.recharts.line_chart( rx.recharts.line( data_key="pv", stroke=rx.color("accent", 9), ), rx.recharts.line( data_key="uv", stroke=rx.color("green", 9), ), rx.recharts.x_axis(type_="number"), rx.recharts.y_axis(data_key="name", type_="category"), layout="vertical", margin={"top": 20, "right": 20, "left": 20, "bottom": 20}, data=data, height=300, width="100%", ) ``` ## Dynamic Data Chart data can be modified by tying the `data` prop to a State var. Most other props, such as `type_`, can be controlled dynamically as well. In the following example the "Munge Data" button can be used to randomly modify the data, and the two `select` elements change the line `type_`. Since the data and style is saved in the per-browser-tab State, the changes will not be visible to other visitors. ```python demo exec initial_data = data class LineChartState(rx.State): data: list[dict[str, Any]] = initial_data pv_type: str = "monotone" uv_type: str = "monotone" @rx.event def set_pv_type(self, pv_type: str): self.pv_type = pv_type @rx.event def set_uv_type(self, uv_type: str): self.uv_type = uv_type @rx.event def munge_data(self): for row in self.data: row["uv"] += random.randint(-500, 500) row["pv"] += random.randint(-1000, 1000) def line_dynamic(): return rx.vstack( rx.recharts.line_chart( rx.recharts.line( data_key="pv", type_=LineChartState.pv_type, stroke="#8884d8", ), rx.recharts.line( data_key="uv", type_=LineChartState.uv_type, stroke="#82ca9d", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=LineChartState.data, margin={"top": 20, "right": 20, "left": 20, "bottom": 20}, width="100%", height=300, ), rx.hstack( rx.button("Munge Data", on_click=LineChartState.munge_data), rx.select( ["monotone", "linear", "step", "stepBefore", "stepAfter"], value=LineChartState.pv_type, on_change=LineChartState.set_pv_type, ), rx.select( ["monotone", "linear", "step", "stepBefore", "stepAfter"], value=LineChartState.uv_type, on_change=LineChartState.set_uv_type, ), ), width="100%", ) ``` To learn how to use the `sync_id`, `x_axis_id` and `y_axis_id` props check out the of the area chart [documentation](/docs/library/graphing/charts/areachart), where these props are all described with examples. ## API Reference ### rx.recharts.LineChart A Line chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `data` | Sequence[dict[str, Any]] | - | The source data, in which each element is an object. | | `margin` | dict[str, Any] | - | The sizes of whitespace around the chart, i.e. {"top": 50, "right": 30, "left": 20, "bottom": 5}. | | `sync_id` | str | - | If any two categorical charts(rx.line_chart, rx.area_chart, rx.bar_chart, rx.composed_chart) have the same sync_id, these two charts can sync the position GraphingTooltip, and the start_index, end_index of Brush. | | `sync_method` | Literal["index", "value"] | `"index"` | When sync_id is provided, allows customisation of how the charts will synchronize GraphingTooltips and brushes. Using 'index' (default setting), other charts will reuse current datum's index within the data array. In cases where data does not have the same length, this might yield unexpected results. In that case use 'value' which will try to match other charts values, or a fully custom function which will receive tick, data as argument and should return an index. 'index', 'value', function. | | `layout` | Literal["vertical", "horizontal"] | `"horizontal"` | The layout of area in the chart. 'horizontal', 'vertical'. | | `stack_offset` | Literal["expand", "none", "wiggle", "silhouette"] | - | The type of offset function used to generate the lower and upper values in the series array. The four types are built-in offsets in d3-shape. 'expand', 'none', 'wiggle', 'silhouette'. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.Line A Line component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `layout` | Literal["vertical", "horizontal"] | - | The layout of bar in the chart, usually inherited from parent. 'horizontal', 'vertical'. | | `data_key` | str, int | - | The key of a group of data which should be unique in an area chart. | | `x_axis_id` | str, int | `0` | The id of x-axis which is corresponding to the data. | | `y_axis_id` | str, int | `0` | The id of y-axis which is corresponding to the data. | | `legend_type` | Literal["circle", "cross", "diamond", "line", "plainline", "rect", "square", "star", "triangle", "wye", "none"] | - | The type of icon in legend. If set to 'none', no legend item will be rendered. 'line', 'plainline', 'square', 'rect'\| 'circle', 'cross', 'diamond', 'star', 'triangle', 'wye', 'none' optional. | | `label` | dict[str, Any], bool | `False` | If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. | | `is_animation_active` | bool | `True` | If set false, animation of bar will be disabled. | | `animation_begin` | int | `0` | Specifies when the animation should begin, the unit of this option is ms. | | `animation_duration` | int | `1500` | Specifies the duration of animation, the unit of this option is ms. | | `animation_easing` | Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] | `"ease"` | The type of easing function. | | `unit` | str, int | - | The unit of data. This option will be used in tooltip. | | `name` | str, int | - | The name of data. This option will be used in tooltip and legend to represent the component. If no value was set to this option, the value of dataKey will be used alternatively. | | `type_` | Literal["basis", "basisClosed", "basisOpen", "bumpX", "bumpY", "bump", "linear", "linearClosed", "natural", "monotoneX", "monotoneY", "monotone", "step", "stepBefore", "stepAfter"] | - | The interpolation type of line. And customized interpolation function can be set to type. It's the same as type in Area. | | `stroke` | str, Color | `rx.color("accent", 9)` | The color of the line stroke. | | `stroke_width` | str, int, float | `1` | The width of the line stroke. | | `dot` | dict[str, Any], bool | `{"stroke": rx.color("accent", 10), "fill": rx.color("accent", 4)}` | The dot is shown when mouse enter a line chart and this chart has tooltip. If false set, no active dot will not be drawn. If true set, active dot will be drawn which have the props calculated internally. | | `active_dot` | dict[str, Any], bool | `{"stroke": rx.color("accent", 2), "fill": rx.color("accent", 10)}` | The dot is shown when user enter an area chart and this chart has tooltip. If false set, no active dot will not be drawn. If true set, active dot will be drawn which have the props calculated internally. | | `hide` | bool | `False` | Hides the line when true, useful when toggling visibility state via legend. | | `connect_nulls` | bool | - | Whether to connect a graph line across null points. | | `points` | Sequence[dict[str, Any]] | - | The coordinates of all the points in the line, usually calculated internally. | | `stroke_dasharray` | str | - | The pattern of dashes and gaps used to paint the line. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_animation_start` | The customized event handler of animation start. | | `on_animation_end` | The customized event handler of animation end. | # Pie Chart Source: http://localhost:3000/docs/library/graphing/charts/piechart.md --- components: - rx.recharts.PieChart - rx.recharts.Pie --- ```python exec import reflex as rx ``` A pie chart is a circular statistical graphic which is divided into slices to illustrate numerical proportion. For a pie chart we must define an `rx.recharts.pie()` component for each set of values we wish to plot. Each `rx.recharts.pie()` component has a `data`, a `data_key` and a `name_key` which clearly states which data and which variables in our data we are tracking. In this simple example we plot `value` column as our `data_key` against the `name` column which we set as our `name_key`. We also use the `fill` prop to set the color of the pie slices. ```python demo graphing data01 = [ {"name": "Group A", "value": 400}, {"name": "Group B", "value": 300, "fill": "#AC0E08FF"}, {"name": "Group C", "value": 300, "fill": "rgb(80,40, 190)"}, {"name": "Group D", "value": 200, "fill": rx.color("yellow", 10)}, {"name": "Group E", "value": 278, "fill": "purple"}, {"name": "Group F", "value": 189, "fill": "orange"}, ] def pie_simple(): return rx.recharts.pie_chart( rx.recharts.pie( data=data01, data_key="value", name_key="name", fill="#8884d8", label=True, ), width="100%", height=300, ) ``` We can also add two pies on one chart by using two `rx.recharts.pie` components. In this example `inner_radius` and `outer_radius` props are used. They define the doughnut shape of a pie chart: `inner_radius` creates the hollow center (use "0%" for a full pie), while `outer_radius` sets the overall size. The `padding_angle` prop, used on the green pie below, adds space between pie slices, enhancing visibility of individual segments. ```python demo graphing data01 = [ {"name": "Group A", "value": 400}, {"name": "Group B", "value": 300}, {"name": "Group C", "value": 300}, {"name": "Group D", "value": 200}, {"name": "Group E", "value": 278}, {"name": "Group F", "value": 189}, ] data02 = [ {"name": "Group A", "value": 2400}, {"name": "Group B", "value": 4567}, {"name": "Group C", "value": 1398}, {"name": "Group D", "value": 9800}, {"name": "Group E", "value": 3908}, {"name": "Group F", "value": 4800}, ] def pie_double(): return rx.recharts.pie_chart( rx.recharts.pie( data=data01, data_key="value", name_key="name", fill="#82ca9d", inner_radius="60%", padding_angle=5, ), rx.recharts.pie( data=data02, data_key="value", name_key="name", fill="#8884d8", outer_radius="50%", ), rx.recharts.graphing_tooltip(), width="100%", height=300, ) ``` ## Dynamic Data Chart data tied to a State var causes the chart to automatically update when the state changes, providing a nice way to visualize data in response to user interface elements. View the "Data" tab to see the substate driving this half-pie chart. ```python demo exec from typing import Any class PieChartState(rx.State): resources: list[dict[str, Any]] = [ dict(type_="🏆", count=1), dict(type_="🪵", count=1), dict(type_="🥑", count=1), dict(type_="🧱", count=1), ] @rx.var(cache=True) def resource_types(self) -> list[str]: return [r["type_"] for r in self.resources] @rx.event def increment(self, type_: str): for resource in self.resources: if resource["type_"] == type_: resource["count"] += 1 break @rx.event def decrement(self, type_: str): for resource in self.resources: if resource["type_"] == type_ and resource["count"] > 0: resource["count"] -= 1 break def dynamic_pie_example(): return rx.hstack( rx.recharts.pie_chart( rx.recharts.pie( data=PieChartState.resources, data_key="count", name_key="type_", cx="50%", cy="50%", start_angle=180, end_angle=0, fill="#8884d8", label=True, ), rx.recharts.graphing_tooltip(), ), rx.vstack( rx.foreach( PieChartState.resource_types, lambda type_, i: rx.hstack( rx.button("-", on_click=PieChartState.decrement(type_)), rx.text(type_, PieChartState.resources[i]["count"]), rx.button("+", on_click=PieChartState.increment(type_)), ), ), ), width="100%", height="15em", ) ``` ## API Reference ### rx.recharts.PieChart A Pie chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `margin` | dict[str, Any] | - | The sizes of whitespace around the chart, i.e. {"top": 50, "right": 30, "left": 20, "bottom": 5}. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.Pie A Pie chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `data` | Sequence[dict[str, Any]] | - | The source data which each element is an object. | | `data_key` | str, int | - | The key of each sector's value. | | `cx` | str, int | `"50%"` | The x-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of container width. | | `cy` | str, int | `"50%"` | The y-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of container height. | | `inner_radius` | str, int | `0` | The inner radius of pie, which can be set to a percent value. | | `outer_radius` | str, int | `"80%"` | The outer radius of pie, which can be set to a percent value. | | `start_angle` | int | `0` | The angle of first sector. | | `end_angle` | int | `360` | The end angle of last sector, which should be unequal to start_angle. | | `min_angle` | int | `0` | The minimum angle of each unzero data. | | `padding_angle` | int | `0` | The angle between two sectors. | | `name_key` | str | `"name"` | The key of each sector's name. | | `legend_type` | Literal["circle", "cross", "diamond", "line", "plainline", "rect", "square", "star", "triangle", "wye", "none"] | `"rect"` | The type of icon in legend. If set to 'none', no legend item will be rendered. | | `label` | dict[str, Any], bool | `False` | If false set, labels will not be drawn. If true set, labels will be drawn which have the props calculated internally. | | `label_line` | dict[str, Any], bool | `False` | If false set, label lines will not be drawn. If true set, label lines will be drawn which have the props calculated internally. | | `stroke` | str, Color | `rx.color("accent", 9)` | Stoke color. | | `fill` | str, Color | `rx.color("accent", 3)` | Fill color. | | `is_animation_active` | bool | `true in CSR, and false in SSR` | If set false, animation of tooltip will be disabled. | | `animation_begin` | int | `400` | Specifies when the animation should begin, the unit of this option is ms. | | `animation_duration` | int | `1500` | Specifies the duration of animation, the unit of this option is ms. | | `animation_easing` | Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] | `"ease"` | The type of easing function. | | `root_tab_index` | int | `0` | The tabindex of wrapper surrounding the cells. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_animation_start` | | | `on_animation_end` | | # Radar Chart Source: http://localhost:3000/docs/library/graphing/charts/radarchart.md --- components: - rx.recharts.RadarChart - rx.recharts.Radar --- ```python exec import reflex as rx from typing import Any ``` A radar chart shows multivariate data of three or more quantitative variables mapped onto an axis. ## Simple Example For a radar chart we must define an `rx.recharts.radar()` component for each set of values we wish to plot. Each `rx.recharts.radar()` component has a `data_key` which clearly states which variable in our data we are plotting. In this simple example we plot the `A` column of our data against the `subject` column which we set as the `data_key` in `rx.recharts.polar_angle_axis`. ```python demo graphing data = [ {"subject": "Math", "A": 120, "B": 110, "fullMark": 150}, {"subject": "Chinese", "A": 98, "B": 130, "fullMark": 150}, {"subject": "English", "A": 86, "B": 130, "fullMark": 150}, {"subject": "Geography", "A": 99, "B": 100, "fullMark": 150}, {"subject": "Physics", "A": 85, "B": 90, "fullMark": 150}, {"subject": "History", "A": 65, "B": 85, "fullMark": 150}, ] def radar_simple(): return rx.recharts.radar_chart( rx.recharts.radar( data_key="A", stroke="#8884d8", fill="#8884d8", ), rx.recharts.polar_grid(), rx.recharts.polar_angle_axis(data_key="subject"), rx.recharts.polar_radius_axis(angle=90, domain=[0, 150]), data=data, width="100%", height=300, ) ``` ## Multiple Radars We can also add two radars on one chart by using two `rx.recharts.radar` components. In this plot an `inner_radius` and an `outer_radius` are set which determine the chart's size and shape. The `inner_radius` sets the distance from the center to the innermost part of the chart (creating a hollow center if greater than zero), while the `outer_radius` defines the chart's overall size by setting the distance from the center to the outermost edge of the radar plot. ```python demo graphing data = [ {"subject": "Math", "A": 120, "B": 110, "fullMark": 150}, {"subject": "Chinese", "A": 98, "B": 130, "fullMark": 150}, {"subject": "English", "A": 86, "B": 130, "fullMark": 150}, {"subject": "Geography", "A": 99, "B": 100, "fullMark": 150}, {"subject": "Physics", "A": 85, "B": 90, "fullMark": 150}, {"subject": "History", "A": 65, "B": 85, "fullMark": 150}, ] def radar_multiple(): return rx.recharts.radar_chart( rx.recharts.radar( data_key="A", stroke="#8884d8", fill="#8884d8", ), rx.recharts.radar( data_key="B", stroke="#82ca9d", fill="#82ca9d", fill_opacity=0.6, ), rx.recharts.polar_grid(), rx.recharts.polar_angle_axis(data_key="subject"), rx.recharts.polar_radius_axis(angle=90, domain=[0, 150]), rx.recharts.legend(), data=data, inner_radius="15%", outer_radius="80%", width="100%", height=300, ) ``` ## Using More Props The `dot` prop shows points at each data vertex when true. `legend_type="line"` displays a line in the chart legend. `animation_begin=0` starts the animation immediately, `animation_duration=8000` sets an 8-second animation, and `animation_easing="ease-in"` makes the animation start slowly and speed up. These props control the chart's appearance and animation behavior. ```python demo graphing data = [ {"subject": "Math", "A": 120, "B": 110, "fullMark": 150}, {"subject": "Chinese", "A": 98, "B": 130, "fullMark": 150}, {"subject": "English", "A": 86, "B": 130, "fullMark": 150}, {"subject": "Geography", "A": 99, "B": 100, "fullMark": 150}, {"subject": "Physics", "A": 85, "B": 90, "fullMark": 150}, {"subject": "History", "A": 65, "B": 85, "fullMark": 150}, ] def radar_start_end(): return rx.recharts.radar_chart( rx.recharts.radar( data_key="A", dot=True, stroke="#8884d8", fill="#8884d8", fill_opacity=0.6, legend_type="line", animation_begin=0, animation_duration=8000, animation_easing="ease-in", ), rx.recharts.polar_grid(), rx.recharts.polar_angle_axis(data_key="subject"), rx.recharts.polar_radius_axis(angle=90, domain=[0, 150]), rx.recharts.legend(), data=data, width="100%", height=300, ) ``` # Dynamic Data Chart data tied to a State var causes the chart to automatically update when the state changes, providing a nice way to visualize data in response to user interface elements. View the "Data" tab to see the substate driving this radar chart of character traits. ```python demo exec class RadarChartState(rx.State): total_points: int = 100 traits: list[dict[str, Any]] = [ dict(trait="Strength", value=15), dict(trait="Dexterity", value=15), dict(trait="Constitution", value=15), dict(trait="Intelligence", value=15), dict(trait="Wisdom", value=15), dict(trait="Charisma", value=15), ] @rx.var def remaining_points(self) -> int: return self.total_points - sum(t["value"] for t in self.traits) @rx.var(cache=True) def trait_names(self) -> list[str]: return [t["trait"] for t in self.traits] @rx.event def set_trait(self, trait: str, value: int): for t in self.traits: if t["trait"] == trait: available_points = self.remaining_points + t["value"] value = min(value, available_points) t["value"] = value break def radar_dynamic(): return rx.hstack( rx.recharts.radar_chart( rx.recharts.radar( data_key="value", stroke="#8884d8", fill="#8884d8", ), rx.recharts.polar_grid(), rx.recharts.polar_angle_axis(data_key="trait"), data=RadarChartState.traits, ), rx.vstack( rx.foreach( RadarChartState.trait_names, lambda trait_name, i: rx.hstack( rx.text(trait_name, width="7em"), rx.slider( default_value=RadarChartState.traits[i]["value"].to(int), on_change=lambda value: RadarChartState.set_trait( trait_name, value[0] ), width="25vw", ), rx.text(RadarChartState.traits[i]["value"]), ), ), rx.text("Remaining points: ", RadarChartState.remaining_points), ), width="100%", height="15em", ) ``` ## API Reference ### rx.recharts.RadarChart A Radar chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `data` | Sequence[dict[str, Any]] | - | The source data, in which each element is an object. | | `margin` | dict[str, Any] | `{"top": 0, "right": 0, "left": 0, "bottom": 0}` | The sizes of whitespace around the chart, i.e. {"top": 50, "right": 30, "left": 20, "bottom": 5}. | | `cx` | str, int | `"50%"` | The The x-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of width. Number, Percentage. | | `cy` | str, int | `"50%"` | The The y-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of height. Number, Percentage. | | `start_angle` | int | `90` | The angle of first radial direction line. | | `end_angle` | int | `-270` | The angle of last point in the circle which should be startAngle - 360 or startAngle + 360. We'll calculate the direction of chart by 'startAngle' and 'endAngle'. | | `inner_radius` | str, int | `0` | The inner radius of first circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number, Percentage. | | `outer_radius` | str, int | `"80%"` | The outer radius of last circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number, Percentage. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.Radar A Radar chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `data_key` | str, int | - | The key of a group of data which should be unique in a radar chart. | | `points` | Sequence[dict[str, Any]] | - | The coordinates of all the vertices of the radar shape, like [{ x, y }]. | | `dot` | dict[str, Any], bool | `True` | If false set, dots will not be drawn. | | `stroke` | str, Color | `rx.color("accent", 9)` | Stoke color. | | `fill` | str, Color | `rx.color("accent", 3)` | Fill color. | | `fill_opacity` | float | `0.6` | The opacity to fill the chart. | | `legend_type` | Literal["circle", "cross", "diamond", "line", "plainline", "rect", "square", "star", "triangle", "wye", "none"] | `"rect"` | The type of icon in legend. If set to 'none', no legend item will be rendered. | | `label` | dict[str, Any], bool | `True` | If false set, labels will not be drawn. | | `is_animation_active` | bool | `True in CSR, and False in SSR` | If set false, animation of polygon will be disabled. | | `animation_begin` | int | `0` | Specifies when the animation should begin, the unit of this option is ms. | | `animation_duration` | int | `1500` | Specifies the duration of animation, the unit of this option is ms. | | `animation_easing` | Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] | `"ease"` | The type of easing function. 'ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear'. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_animation_start` | | | `on_animation_end` | | # Radial Bar Chart Source: http://localhost:3000/docs/library/graphing/charts/radialbarchart.md --- components: - rx.recharts.RadialBarChart --- ```python exec import reflex as rx ``` ## Simple Example This example demonstrates how to use a `radial_bar_chart` with a `radial_bar`. The `radial_bar_chart` takes in `data` and then the `radial_bar` takes in a `data_key`. A radial bar chart is a circular visualization where data categories are represented by bars extending outward from a central point, with the length of each bar proportional to its value. ```md alert info # Fill color supports `rx.color()`, which automatically adapts to dark/light mode changes. ``` ```python demo graphing data = [ {"name": "C", "x": 3, "fill": rx.color("cyan", 9)}, {"name": "D", "x": 4, "fill": rx.color("blue", 9)}, {"name": "E", "x": 5, "fill": rx.color("orange", 9)}, {"name": "F", "x": 6, "fill": rx.color("red", 9)}, {"name": "G", "x": 7, "fill": rx.color("gray", 9)}, {"name": "H", "x": 8, "fill": rx.color("green", 9)}, {"name": "I", "x": 9, "fill": rx.color("accent", 6)}, ] def radial_bar_simple(): return rx.recharts.radial_bar_chart( rx.recharts.radial_bar( data_key="x", min_angle=15, ), data=data, width="100%", height=500, ) ``` ## Advanced Example The `start_angle` and `end_angle` define the circular arc over which the bars are distributed, while `inner_radius` and `outer_radius` determine the radial extent of the bars from the center. ```python demo graphing data_radial_bar = [ {"name": "18-24", "uv": 31.47, "pv": 2400, "fill": "#8884d8"}, {"name": "25-29", "uv": 26.69, "pv": 4567, "fill": "#83a6ed"}, {"name": "30-34", "uv": -15.69, "pv": 1398, "fill": "#8dd1e1"}, {"name": "35-39", "uv": 8.22, "pv": 9800, "fill": "#82ca9d"}, {"name": "40-49", "uv": -8.63, "pv": 3908, "fill": "#a4de6c"}, {"name": "50+", "uv": -2.63, "pv": 4800, "fill": "#d0ed57"}, {"name": "unknown", "uv": 6.67, "pv": 4800, "fill": "#ffc658"}, ] def radial_bar_advanced(): return rx.recharts.radial_bar_chart( rx.recharts.radial_bar( data_key="uv", min_angle=90, background=True, label={"fill": "#666", "position": "insideStart"}, ), data=data_radial_bar, inner_radius="10%", outer_radius="80%", start_angle=180, end_angle=0, width="100%", height=300, ) ``` ## API Reference ### rx.recharts.RadialBarChart A RadialBar chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `data` | Sequence[dict[str, Any]] | - | The source data which each element is an object. | | `margin` | dict[str, Any] | `{"top": 5, "right": 5, "left": 5 "bottom": 5}` | The sizes of whitespace around the chart. | | `cx` | str, int | `"50%"` | The The x-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of width. Number, Percentage. | | `cy` | str, int | `"50%"` | The The y-coordinate of center. If set a percentage, the final value is obtained by multiplying the percentage of height. Number, Percentage. | | `start_angle` | int | `0` | The angle of first radial direction line. | | `end_angle` | int | `360` | The angle of last point in the circle which should be startAngle - 360 or startAngle + 360. We'll calculate the direction of chart by 'startAngle' and 'endAngle'. | | `inner_radius` | str, int | `"30%"` | The inner radius of first circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number, Percentage. | | `outer_radius` | str, int | `"100%"` | The outer radius of last circle grid. If set a percentage, the final value is obtained by multiplying the percentage of maxRadius which is calculated by the width, height, cx, cy. Number, Percentage. | | `bar_category_gap` | str, int | `"10%"` | The gap between two bar categories, which can be a percent value or a fixed value. Percentage, Number. | | `bar_gap` | str | `4` | The gap between two bars in the same category, which can be a percent value or a fixed value. Percentage, Number. | | `bar_size` | int | - | The size of each bar. If the barSize is not specified, the size of bar will be calculated by the barCategoryGap, barGap and the quantity of bar groups. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Scatter Chart Source: http://localhost:3000/docs/library/graphing/charts/scatterchart.md --- components: - rx.recharts.ScatterChart - rx.recharts.Scatter --- ```python exec import reflex as rx ``` A scatter chart always has two value axes to show one set of numerical data along a horizontal (value) axis and another set of numerical values along a vertical (value) axis. The chart displays points at the intersection of an x and y numerical value, combining these values into single data points. ## Simple Example For a scatter chart we must define an `rx.recharts.scatter()` component for each set of values we wish to plot. Each `rx.recharts.scatter()` component has a `data` prop which clearly states which data source we plot. We also must define `rx.recharts.x_axis()` and `rx.recharts.y_axis()` so that the graph knows what data to plot on each axis. ```python demo graphing data01 = [ {"x": 100, "y": 200, "z": 200}, {"x": 120, "y": 100, "z": 260}, {"x": 170, "y": 300, "z": 400}, {"x": 170, "y": 250, "z": 280}, {"x": 150, "y": 400, "z": 500}, {"x": 110, "y": 280, "z": 200}, ] def scatter_simple(): return rx.recharts.scatter_chart( rx.recharts.scatter( data=data01, fill="#8884d8", ), rx.recharts.x_axis(data_key="x", type_="number"), rx.recharts.y_axis(data_key="y"), width="100%", height=300, ) ``` ## Multiple Scatters We can also add two scatters on one chart by using two `rx.recharts.scatter()` components, and we can define an `rx.recharts.z_axis()` which represents a third column of data and is represented by the size of the dots in the scatter plot. ```python demo graphing data01 = [ {"x": 100, "y": 200, "z": 200}, {"x": 120, "y": 100, "z": 260}, {"x": 170, "y": 300, "z": 400}, {"x": 170, "y": 250, "z": 280}, {"x": 150, "y": 350, "z": 500}, {"x": 110, "y": 280, "z": 200}, ] data02 = [ {"x": 200, "y": 260, "z": 240}, {"x": 240, "y": 290, "z": 220}, {"x": 190, "y": 290, "z": 250}, {"x": 198, "y": 250, "z": 210}, {"x": 180, "y": 280, "z": 260}, {"x": 210, "y": 220, "z": 230}, ] def scatter_double(): return rx.recharts.scatter_chart( rx.recharts.scatter(data=data01, fill="#8884d8", name="A"), rx.recharts.scatter(data=data02, fill="#82ca9d", name="B"), rx.recharts.cartesian_grid(stroke_dasharray="3 3"), rx.recharts.x_axis(data_key="x", type_="number"), rx.recharts.y_axis(data_key="y"), rx.recharts.z_axis(data_key="z", range=[60, 400], name="score"), rx.recharts.legend(), rx.recharts.graphing_tooltip(), width="100%", height=300, ) ``` To learn how to use the `x_axis_id` and `y_axis_id` props, check out the Multiple Axis section of the area chart [documentation](/docs/library/graphing/charts/areachart). ## Dynamic Data Chart data tied to a State var causes the chart to automatically update when the state changes, providing a nice way to visualize data in response to user interface elements. View the "Data" tab to see the substate driving this calculation of iterations in the Collatz Conjecture for a given starting number. Enter a starting number in the box below the chart to recalculate. ```python demo exec class ScatterChartState(rx.State): data: list[dict[str, int]] = [] @rx.event def compute_collatz(self, form_data: dict) -> int: n = int(form_data.get("start") or 1) yield rx.set_value("start", "") self.data = [] for ix in range(400): self.data.append({"x": ix, "y": n}) if n == 1: break if n % 2 == 0: n = n // 2 else: n = 3 * n + 1 def scatter_dynamic(): return rx.vstack( rx.recharts.scatter_chart( rx.recharts.scatter( data=ScatterChartState.data, fill="#8884d8", ), rx.recharts.x_axis(data_key="x", type_="number"), rx.recharts.y_axis(data_key="y", type_="number"), ), rx.form.root( rx.input(placeholder="Enter a number", id="start"), rx.button("Compute", type="submit"), on_submit=ScatterChartState.compute_collatz, ), width="100%", height="15em", on_mount=ScatterChartState.compute_collatz({"start": "15"}), ) ``` ## Legend Type and Shape ```python demo exec class ScatterChartState2(rx.State): legend_types: list[str] = [ "square", "circle", "cross", "diamond", "star", "triangle", "wye", ] legend_type: str = "circle" shapes: list[str] = [ "square", "circle", "cross", "diamond", "star", "triangle", "wye", ] shape: str = "circle" data01 = [ {"x": 100, "y": 200, "z": 200}, {"x": 120, "y": 100, "z": 260}, {"x": 170, "y": 300, "z": 400}, {"x": 170, "y": 250, "z": 280}, {"x": 150, "y": 400, "z": 500}, {"x": 110, "y": 280, "z": 200}, ] @rx.event def set_shape(self, shape: str): self.shape = shape @rx.event def set_legend_type(self, legend_type: str): self.legend_type = legend_type def scatter_shape(): return rx.vstack( rx.recharts.scatter_chart( rx.recharts.scatter( data=data01, fill="#8884d8", legend_type=ScatterChartState2.legend_type, shape=ScatterChartState2.shape, ), rx.recharts.x_axis(data_key="x", type_="number"), rx.recharts.y_axis(data_key="y"), rx.recharts.legend(), width="100%", height=300, ), rx.hstack( rx.text("Legend Type: "), rx.select( ScatterChartState2.legend_types, value=ScatterChartState2.legend_type, on_change=ScatterChartState2.set_legend_type, ), rx.text("Shape: "), rx.select( ScatterChartState2.shapes, value=ScatterChartState2.shape, on_change=ScatterChartState2.set_shape, ), ), width="100%", ) ``` ## API Reference ### rx.recharts.ScatterChart A Scatter chart component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `width` | str, int | - | The width of chart container. String or Integer. | | `height` | str, int | - | The height of chart container. | | `margin` | dict[str, Any] | `{"top": 5, "right": 5, "bottom": 5, "left": 5}` | The sizes of whitespace around the chart. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.Scatter A Scatter component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `data` | Sequence[dict[str, Any]] | - | The source data, in which each element is an object. | | `name` | str | - | The name of the data. It is used to represent the scatter in legend. | | `legend_type` | Literal["circle", "cross", "diamond", "line", "plainline", "rect", "square", "star", "triangle", "wye", "none"] | `"circle"` | The type of icon in legend. If set to 'none', no legend item will be rendered. 'line', 'plainline', 'square', 'rect'\| 'circle', 'cross', 'diamond', 'square', 'star', 'triangle', 'wye', 'none'. | | `x_axis_id` | str, int | `0` | The id of x-axis which is corresponding to the data. | | `y_axis_id` | str, int | `0` | The id of y-axis which is corresponding to the data. | | `z_axis_id` | str, int | `0` | The id of z-axis which is corresponding to the data. | | `line` | bool | `False` | If false set, line will not be drawn. If true set, line will be drawn which have the props calculated internally. | | `shape` | Literal["square", "circle", "cross", "diamond", "star", "triangle", "wye"] | `"circle"` | If a string set, specified symbol will be used to show scatter item. 'circle', 'cross', 'diamond', 'square', 'star', 'triangle', 'wye'. | | `line_type` | Literal["joint", "fitting"] | `"joint"` | If 'joint' set, line will generated by just jointing all the points. If 'fitting' set, line will be generated by fitting algorithm. 'joint', 'fitting'. | | `fill` | str, Color | `rx.color("accent", 9)` | The fill color of the scatter. | | `is_animation_active` | bool | `True in CSR, False in SSR` | If set false, animation of bar will be disabled. | | `animation_begin` | int | `0` | Specifies when the animation should begin, the unit of this option is ms. | | `animation_duration` | int | `1500` | Specifies the duration of animation, the unit of this option is ms. | | `animation_easing` | Literal["ease", "ease-in", "ease-out", "ease-in-out", "linear"] | `"ease"` | The type of easing function. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Axis Source: http://localhost:3000/docs/library/graphing/general/axis.md --- components: - rx.recharts.XAxis - rx.recharts.YAxis - rx.recharts.ZAxis --- ```python exec import reflex as rx ``` The Axis component in Recharts is a powerful tool for customizing and configuring the axes of your charts. It provides a wide range of props that allow you to control the appearance, behavior, and formatting of the axis. Whether you're working with an AreaChart, LineChart, or any other chart type, the Axis component enables you to create precise and informative visualizations. ## Basic Example ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def axis_simple(): return rx.recharts.area_chart( rx.recharts.area( data_key="uv", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.x_axis( data_key="name", label={"value": "Pages", "position": "bottom"}, ), rx.recharts.y_axis( data_key="uv", label={"value": "Views", "angle": -90, "position": "left"}, ), data=data, width="100%", height=300, margin={ "bottom": 40, "left": 40, "right": 40, }, ) ``` ## Multiple Axes Multiple axes can be used for displaying different data series with varying scales or units on the same chart. This allows for a more comprehensive comparison and analysis of the data. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def multi_axis(): return rx.recharts.area_chart( rx.recharts.area( data_key="uv", stroke="#8884d8", fill="#8884d8", y_axis_id="left", ), rx.recharts.area( data_key="pv", y_axis_id="right", type_="monotone", stroke="#82ca9d", fill="#82ca9d", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(data_key="uv", y_axis_id="left"), rx.recharts.y_axis(data_key="pv", y_axis_id="right", orientation="right"), rx.recharts.graphing_tooltip(), rx.recharts.legend(), data=data, width="100%", height=300, ) ``` ## Choosing Location of Labels for Axes The axes `label` can take several positions. The example below allows you to try out different locations for the x and y axis labels. ```python demo graphing class AxisState(rx.State): label_positions: list[str] = [ "center", "insideTopLeft", "insideTopRight", "insideBottomRight", "insideBottomLeft", "insideTop", "insideBottom", "insideLeft", "insideRight", "outside", "top", "bottom", "left", "right", ] label_offsets: list[str] = ["-30", "-20", "-10", "0", "10", "20", "30"] x_axis_position: str = "bottom" x_axis_offset: int y_axis_position: str = "left" y_axis_offset: int @rx.event def set_y_axis_position(self, position: str): self.y_axis_position = position @rx.event def set_x_axis_position(self, position: str): self.x_axis_position = position @rx.event def set_x_axis_offset(self, offset: str): self.x_axis_offset = int(offset) @rx.event def set_y_axis_offset(self, offset: str): self.y_axis_offset = int(offset) data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def axis_labels(): return rx.vstack( rx.recharts.area_chart( rx.recharts.area( data_key="uv", stroke=rx.color("accent", 9), fill=rx.color("accent", 8), ), rx.recharts.x_axis( data_key="name", label={ "value": "Pages", "position": AxisState.x_axis_position, "offset": AxisState.x_axis_offset, }, ), rx.recharts.y_axis( data_key="uv", label={ "value": "Views", "angle": -90, "position": AxisState.y_axis_position, "offset": AxisState.y_axis_offset, }, ), data=data, width="100%", height=300, margin={ "bottom": 40, "left": 40, "right": 40, }, ), rx.hstack( rx.text("X Label Position: "), rx.select( AxisState.label_positions, value=AxisState.x_axis_position, on_change=AxisState.set_x_axis_position, ), rx.text("X Label Offset: "), rx.select( AxisState.label_offsets, value=AxisState.x_axis_offset.to_string(), on_change=AxisState.set_x_axis_offset, ), rx.text("Y Label Position: "), rx.select( AxisState.label_positions, value=AxisState.y_axis_position, on_change=AxisState.set_y_axis_position, ), rx.text("Y Label Offset: "), rx.select( AxisState.label_offsets, value=AxisState.y_axis_offset.to_string(), on_change=AxisState.set_y_axis_offset, ), ), width="100%", ) ``` ## API Reference ### rx.recharts.XAxis An XAxis component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `data_key` | str, int | - | The key of data displayed in the axis. | | `hide` | bool | `False` | If set true, the axis do not display in the chart. | | `width` | str, int | - | The width of axis which is usually calculated internally. | | `height` | str, int | - | The height of axis, which can be set by user. | | `type_` | Literal["auto", "number", "category"] | - | The type of axis 'number', 'category'. | | `interval` | Literal["preserveStart", "preserveEnd", "preserveStartEnd", "equidistantPreserveStart"], int | `"preserveEnd"` | If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. | | `allow_decimals` | bool | `True` | Allow the ticks of Axis to be decimals or not. | | `allow_data_overflow` | bool | `False` | When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. | | `allow_duplicated_category` | bool | `True` | Allow the axis has duplicated categorys or not when the type of axis is "category". | | `domain` | Sequence | `[0, "auto"]` | The range of the axis. Work best in conjunction with allow_data_overflow. | | `axis_line` | bool | `True` | If set false, no axis line will be drawn. | | `mirror` | bool | `False` | If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. | | `reversed` | bool | `False` | Reverse the ticks or not. | | `label` | str, int, dict[str, Any] | - | The label of axis, which appears next to the axis. | | `scale` | Literal["auto", "linear", "pow", "sqrt", "log", "identity", "time", "band", "point", "ordinal", "quantile", "quantize", "utc", "sequential", "threshold"] | `"auto"` | If 'auto' set, the scale function is decided by the type of chart, and the props type. 'auto', 'linear', 'pow', 'sqrt', 'log', 'identity', 'time', 'band', 'point', 'ordinal', 'quantile', 'quantize', 'utc', 'sequential', 'threshold'. | | `unit` | str, int | - | The unit of data displayed in the axis. This option will be used to represent an index unit in a scatter chart. | | `name` | str, int | - | The name of data displayed in the axis. This option will be used to represent an index in a scatter chart. | | `ticks` | Sequence[str, int] | - | Set the values of axis ticks manually. | | `tick` | bool, dict | - | If set false, no ticks will be drawn. | | `tick_count` | int | `5` | The count of axis ticks. Not used if 'type' is 'category'. | | `tick_line` | bool | `True` | If set false, no axis tick lines will be drawn. | | `tick_size` | int | `6` | The length of tick line. | | `min_tick_gap` | int | `5` | The minimum gap between two adjacent labels. | | `stroke` | str, Color | `rx.color("gray", 9)` | The stroke color of axis. | | `text_anchor` | Literal["start", "middle", "end"] | `"middle"` | The text anchor of axis. | | `orientation` | Literal["top", "bottom"] | `"bottom"` | The orientation of axis 'top', 'bottom'. | | `x_axis_id` | str, int | `0` | The id of x-axis which is corresponding to the data. | | `include_hidden` | bool | `False` | Ensures that all datapoints within a chart contribute to its domain calculation, even when they are hidden. | | `angle` | int | `0` | The angle of axis ticks. | | `padding` | dict[str, int] | `{"left": 0, "right": 0}` | Specify the padding of x-axis. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.YAxis A YAxis component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `data_key` | str, int | - | The key of data displayed in the axis. | | `hide` | bool | `False` | If set true, the axis do not display in the chart. | | `width` | str, int | - | The width of axis which is usually calculated internally. | | `height` | str, int | - | The height of axis, which can be set by user. | | `type_` | Literal["auto", "number", "category"] | - | The type of axis 'number', 'category'. | | `interval` | Literal["preserveStart", "preserveEnd", "preserveStartEnd", "equidistantPreserveStart"], int | `"preserveEnd"` | If set 0, all the ticks will be shown. If set preserveStart", "preserveEnd" or "preserveStartEnd", the ticks which is to be shown or hidden will be calculated automatically. | | `allow_decimals` | bool | `True` | Allow the ticks of Axis to be decimals or not. | | `allow_data_overflow` | bool | `False` | When domain of the axis is specified and the type of the axis is 'number', if allowDataOverflow is set to be false, the domain will be adjusted when the minimum value of data is smaller than domain[0] or the maximum value of data is greater than domain[1] so that the axis displays all data values. If set to true, graphic elements (line, area, bars) will be clipped to conform to the specified domain. | | `allow_duplicated_category` | bool | `True` | Allow the axis has duplicated categorys or not when the type of axis is "category". | | `domain` | Sequence | `[0, "auto"]` | The range of the axis. Work best in conjunction with allow_data_overflow. | | `axis_line` | bool | `True` | If set false, no axis line will be drawn. | | `mirror` | bool | `False` | If set true, flips ticks around the axis line, displaying the labels inside the chart instead of outside. | | `reversed` | bool | `False` | Reverse the ticks or not. | | `label` | str, int, dict[str, Any] | - | The label of axis, which appears next to the axis. | | `scale` | Literal["auto", "linear", "pow", "sqrt", "log", "identity", "time", "band", "point", "ordinal", "quantile", "quantize", "utc", "sequential", "threshold"] | `"auto"` | If 'auto' set, the scale function is decided by the type of chart, and the props type. 'auto', 'linear', 'pow', 'sqrt', 'log', 'identity', 'time', 'band', 'point', 'ordinal', 'quantile', 'quantize', 'utc', 'sequential', 'threshold'. | | `unit` | str, int | - | The unit of data displayed in the axis. This option will be used to represent an index unit in a scatter chart. | | `name` | str, int | - | The name of data displayed in the axis. This option will be used to represent an index in a scatter chart. | | `ticks` | Sequence[str, int] | - | Set the values of axis ticks manually. | | `tick` | bool, dict | - | If set false, no ticks will be drawn. | | `tick_count` | int | `5` | The count of axis ticks. Not used if 'type' is 'category'. | | `tick_line` | bool | `True` | If set false, no axis tick lines will be drawn. | | `tick_size` | int | `6` | The length of tick line. | | `min_tick_gap` | int | `5` | The minimum gap between two adjacent labels. | | `stroke` | str, Color | `rx.color("gray", 9)` | The stroke color of axis. | | `text_anchor` | Literal["start", "middle", "end"] | `"middle"` | The text anchor of axis. | | `orientation` | Literal["left", "right"] | `"left"` | The orientation of axis 'left', 'right'. | | `y_axis_id` | str, int | `0` | The id of y-axis which is corresponding to the data. | | `padding` | dict[str, int] | `{"top": 0, "bottom": 0}` | Specify the padding of y-axis. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ ### rx.recharts.ZAxis A ZAxis component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `data_key` | str, int | - | The key of data displayed in the axis. | | `z_axis_id` | str, int | `0` | The unique id of z-axis. | | `range` | Sequence[int] | `[60, 400]` | The range of axis. | | `unit` | str, int | - | The unit of data displayed in the axis. This option will be used to represent an index unit in a scatter chart. | | `name` | str, int | - | The name of data displayed in the axis. This option will be used to represent an index in a scatter chart. | | `scale` | Literal["auto", "linear", "pow", "sqrt", "log", "identity", "time", "band", "point", "ordinal", "quantile", "quantize", "utc", "sequential", "threshold"] | `"auto"` | If 'auto' set, the scale function is decided by the type of chart, and the props type. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Brush Source: http://localhost:3000/docs/library/graphing/general/brush.md --- components: - rx.recharts.Brush --- ```python exec import reflex as rx ``` ## Simple Example The brush component allows us to view charts that have a large number of data points. To view and analyze them efficiently, the brush provides a slider with two handles that helps the viewer to select some range of data points to be displayed. ```python demo graphing data = [ {"name": "1", "uv": 300, "pv": 456}, {"name": "2", "uv": -145, "pv": 230}, {"name": "3", "uv": -100, "pv": 345}, {"name": "4", "uv": -8, "pv": 450}, {"name": "5", "uv": 100, "pv": 321}, {"name": "6", "uv": 9, "pv": 235}, {"name": "7", "uv": 53, "pv": 267}, {"name": "8", "uv": 252, "pv": -378}, {"name": "9", "uv": 79, "pv": -210}, {"name": "10", "uv": 294, "pv": -23}, {"name": "12", "uv": 43, "pv": 45}, {"name": "13", "uv": -74, "pv": 90}, {"name": "14", "uv": -71, "pv": 130}, {"name": "15", "uv": -117, "pv": 11}, {"name": "16", "uv": -186, "pv": 107}, {"name": "17", "uv": -16, "pv": 926}, {"name": "18", "uv": -125, "pv": 653}, {"name": "19", "uv": 222, "pv": 366}, {"name": "20", "uv": 372, "pv": 486}, {"name": "21", "uv": 182, "pv": 512}, {"name": "22", "uv": 164, "pv": 302}, {"name": "23", "uv": 316, "pv": 425}, {"name": "24", "uv": 131, "pv": 467}, {"name": "25", "uv": 291, "pv": -190}, {"name": "26", "uv": -47, "pv": 194}, {"name": "27", "uv": -415, "pv": 371}, {"name": "28", "uv": -182, "pv": 376}, {"name": "29", "uv": -93, "pv": 295}, {"name": "30", "uv": -99, "pv": 322}, {"name": "31", "uv": -52, "pv": 246}, {"name": "32", "uv": 154, "pv": 33}, {"name": "33", "uv": 205, "pv": 354}, {"name": "34", "uv": 70, "pv": 258}, {"name": "35", "uv": -25, "pv": 359}, {"name": "36", "uv": -59, "pv": 192}, {"name": "37", "uv": -63, "pv": 464}, {"name": "38", "uv": -91, "pv": -2}, {"name": "39", "uv": -66, "pv": 154}, {"name": "40", "uv": -50, "pv": 186}, ] def brush_simple(): return rx.recharts.bar_chart( rx.recharts.bar(data_key="uv", stroke="#8884d8", fill="#8884d8"), rx.recharts.bar(data_key="pv", stroke="#82ca9d", fill="#82ca9d"), rx.recharts.brush(data_key="name", height=30, stroke="#8884d8"), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, width="100%", height=300, ) ``` ## Position, Size, and Range This example showcases ways to set the Position, Size, and Range. The `gap` prop provides the spacing between stops on the brush when the graph will refresh. The `start_index` and `end_index` props defines the default range of the brush. `traveller_width` prop specifies the width of each handle ("traveller" in recharts lingo). ```python demo graphing data = [ {"name": "1", "uv": 300, "pv": 456}, {"name": "2", "uv": -145, "pv": 230}, {"name": "3", "uv": -100, "pv": 345}, {"name": "4", "uv": -8, "pv": 450}, {"name": "5", "uv": 100, "pv": 321}, {"name": "6", "uv": 9, "pv": 235}, {"name": "7", "uv": 53, "pv": 267}, {"name": "8", "uv": 252, "pv": -378}, {"name": "9", "uv": 79, "pv": -210}, {"name": "10", "uv": 294, "pv": -23}, {"name": "12", "uv": 43, "pv": 45}, {"name": "13", "uv": -74, "pv": 90}, {"name": "14", "uv": -71, "pv": 130}, {"name": "15", "uv": -117, "pv": 11}, {"name": "16", "uv": -186, "pv": 107}, {"name": "17", "uv": -16, "pv": 926}, {"name": "18", "uv": -125, "pv": 653}, {"name": "19", "uv": 222, "pv": 366}, {"name": "20", "uv": 372, "pv": 486}, {"name": "21", "uv": 182, "pv": 512}, {"name": "22", "uv": 164, "pv": 302}, {"name": "23", "uv": 316, "pv": 425}, {"name": "24", "uv": 131, "pv": 467}, {"name": "25", "uv": 291, "pv": -190}, {"name": "26", "uv": -47, "pv": 194}, {"name": "27", "uv": -415, "pv": 371}, {"name": "28", "uv": -182, "pv": 376}, {"name": "29", "uv": -93, "pv": 295}, {"name": "30", "uv": -99, "pv": 322}, {"name": "31", "uv": -52, "pv": 246}, {"name": "32", "uv": 154, "pv": 33}, {"name": "33", "uv": 205, "pv": 354}, {"name": "34", "uv": 70, "pv": 258}, {"name": "35", "uv": -25, "pv": 359}, {"name": "36", "uv": -59, "pv": 192}, {"name": "37", "uv": -63, "pv": 464}, {"name": "38", "uv": -91, "pv": -2}, {"name": "39", "uv": -66, "pv": 154}, {"name": "40", "uv": -50, "pv": 186}, ] def brush_pos_size_range(): return rx.recharts.area_chart( rx.recharts.area( data_key="uv", stroke="#8884d8", fill="#8884d8", ), rx.recharts.area( data_key="pv", stroke="#82ca9d", fill="#82ca9d", ), rx.recharts.brush( data_key="name", traveller_width=15, start_index=3, end_index=10, stroke=rx.color("mauve", 10), fill=rx.color("mauve", 3), ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), data=data, width="100%", height=200, ) ``` ## API Reference ### rx.recharts.Brush A Brush component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `stroke` | str, Color | `rx.color("gray", 9)` | Stroke color. | | `fill` | str, Color | `rx.color("gray", 2)` | The fill color of brush. | | `data_key` | str, int | - | The key of data displayed in the axis. | | `x` | int | `0` | The x-coordinate of brush. | | `y` | int | `0` | The y-coordinate of brush. | | `width` | int | `0` | The width of brush. | | `height` | int | `40` | The height of brush. | | `data` | Sequence[Any] | - | The original data of a LineChart, a BarChart or an AreaChart. | | `traveller_width` | int | `5` | The width of each traveller. | | `gap` | int | `1` | The data with gap of refreshing chart. If the option is not set, the chart will be refreshed every time. | | `start_index` | int | `0` | The default start index of brush. If the option is not set, the start index will be 0. | | `end_index` | int | - | The default end index of brush. If the option is not set, the end index will be calculated by the length of data. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ Component-specific event triggers: | Event Trigger | Description | | --- | --- | | `on_change` | | # - rx.recharts.CartesianAxis Source: http://localhost:3000/docs/library/graphing/general/cartesiangrid.md --- components: - rx.recharts.CartesianGrid # - rx.recharts.CartesianAxis --- ```python exec import reflex as rx ``` The Cartesian Grid is a component in Recharts that provides a visual reference for data points in charts. It helps users to better interpret the data by adding horizontal and vertical lines across the chart area. ## Simple Example The `stroke_dasharray` prop in Recharts is used to create dashed or dotted lines for various chart elements like lines, axes, or grids. It's based on the SVG stroke-dasharray attribute. The `stroke_dasharray` prop accepts a comma-separated string of numbers that define a repeating pattern of dashes and gaps along the length of the stroke. - `stroke_dasharray="5,5"`: creates a line with 5-pixel dashes and 5-pixel gaps - `stroke_dasharray="10,5,5,5"`: creates a more complex pattern with 10-pixel dashes, 5-pixel gaps, 5-pixel dashes, and 5-pixel gaps Here's a simple example using it on a Line component: ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def cgrid_simple(): return rx.recharts.line_chart( rx.recharts.line( data_key="pv", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), rx.recharts.cartesian_grid(stroke_dasharray="4 4"), data=data, width="100%", height=300, ) ``` ## Hidden Axes A `cartesian_grid` component can be used to hide the horizontal and vertical grid lines in a chart by setting the `horizontal` and `vertical` props to `False`. This can be useful when you want to show the grid lines only on one axis or when you want to create a cleaner look for the chart. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 9800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def cgrid_hidden(): return rx.recharts.area_chart( rx.recharts.area(data_key="uv", stroke="#8884d8", fill="#8884d8"), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), rx.recharts.cartesian_grid( stroke_dasharray="2 4", vertical=False, horizontal=True, ), data=data, width="100%", height=300, ) ``` ## Custom Grid Lines The `horizontal_points` and `vertical_points` props allow you to specify custom grid lines on the chart, offering fine-grained control over the grid's appearance. These props accept arrays of numbers, where each number represents a pixel offset: - For `horizontal_points`, the offset is measured from the top edge of the chart - For `vertical_points`, the offset is measured from the left edge of the chart ```md alert info # **Important**: The values provided to these props are not directly related to the axis values. They represent pixel offsets within the chart's rendering area. ``` Here's an example demonstrating custom grid lines in a scatter chart: ```python demo graphing data2 = [ {"x": 100, "y": 200, "z": 200}, {"x": 120, "y": 100, "z": 260}, {"x": 170, "y": 300, "z": 400}, {"x": 170, "y": 250, "z": 280}, {"x": 150, "y": 400, "z": 500}, {"x": 110, "y": 280, "z": 200}, {"x": 200, "y": 150, "z": 300}, {"x": 130, "y": 350, "z": 450}, {"x": 90, "y": 220, "z": 180}, {"x": 180, "y": 320, "z": 350}, {"x": 140, "y": 230, "z": 320}, {"x": 160, "y": 180, "z": 240}, ] def cgrid_custom(): return rx.recharts.scatter_chart( rx.recharts.scatter( data=data2, fill="#8884d8", ), rx.recharts.x_axis(data_key="x", type_="number"), rx.recharts.y_axis(data_key="y"), rx.recharts.cartesian_grid( stroke_dasharray="3 3", horizontal_points=[0, 25, 50], vertical_points=[65, 90, 115], ), width="100%", height=200, ) ``` Use these props judiciously to enhance data visualization without cluttering the chart. They're particularly useful for highlighting specific data ranges or creating visual reference points. ## API Reference ### rx.recharts.CartesianGrid A CartesianGrid component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `x` | int | `0` | The x-coordinate of grid. | | `y` | int | `0` | The y-coordinate of grid. | | `width` | int | `0` | The width of grid. | | `height` | int | `0` | The height of grid. | | `horizontal` | bool | `True` | The horizontal line configuration. | | `vertical` | bool | `True` | The vertical line configuration. | | `vertical_points` | Sequence[str, int] | `[]` | The x-coordinates in pixel values of all vertical lines. | | `horizontal_points` | Sequence[str, int] | `[]` | The x-coordinates in pixel values of all vertical lines. | | `fill` | str, Color | - | The background of grid. | | `fill_opacity` | float | - | The opacity of the background used to fill the space between grid lines. | | `stroke_dasharray` | str | - | The pattern of dashes and gaps used to paint the lines of the grid. | | `stroke` | str, Color | `rx.color("gray", 7)` | the stroke color of grid. | #### Event Triggers Base event triggers: https://reflex.dev/docs/api-reference/event-triggers/ # Label Source: http://localhost:3000/docs/library/graphing/general/label.md --- components: - rx.recharts.Label - rx.recharts.LabelList --- ```python exec import reflex as rx ``` Label is a component used to display a single label at a specific position within a chart or axis, while LabelList is a component that automatically renders a list of labels for each data point in a chart series, providing a convenient way to display multiple labels without manually positioning each one. ## Simple Example Here's a simple example that demonstrates how you can customize the label of your axis using `rx.recharts.label`. The `value` prop represents the actual text of the label, the `position` prop specifies where the label is positioned within the axis component, and the `offset` prop is used to fine-tune the label's position. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 5800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def label_simple(): return rx.recharts.bar_chart( rx.recharts.cartesian_grid(stroke_dasharray="3 3"), rx.recharts.bar( rx.recharts.label_list(data_key="uv", position="top"), data_key="uv", fill=rx.color("accent", 8), ), rx.recharts.x_axis( rx.recharts.label( value="center", position="center", offset=30, ), rx.recharts.label( value="inside left", position="insideLeft", offset=10, ), rx.recharts.label( value="inside right", position="insideRight", offset=10, ), height=50, ), data=data, margin={ "left": 20, "right": 20, "top": 20, "bottom": 20, }, width="100%", height=250, ) ``` ## Label List Example `rx.recharts.label_list` takes in a `data_key` where we define the data column to plot. ```python demo graphing data = [ {"name": "Page A", "uv": 4000, "pv": 2400, "amt": 2400}, {"name": "Page B", "uv": 3000, "pv": 1398, "amt": 2210}, {"name": "Page C", "uv": 2000, "pv": 5800, "amt": 2290}, {"name": "Page D", "uv": 2780, "pv": 3908, "amt": 2000}, {"name": "Page E", "uv": 1890, "pv": 4800, "amt": 2181}, {"name": "Page F", "uv": 2390, "pv": 3800, "amt": 2500}, {"name": "Page G", "uv": 3490, "pv": 4300, "amt": 2100}, ] def label_list(): return rx.recharts.bar_chart( rx.recharts.bar( rx.recharts.label_list(data_key="uv", position="top"), data_key="uv", stroke="#8884d8", fill="#8884d8", ), rx.recharts.bar( rx.recharts.label_list(data_key="pv", position="top"), data_key="pv", stroke="#82ca9d", fill="#82ca9d", ), rx.recharts.x_axis(data_key="name"), rx.recharts.y_axis(), margin={"left": 10, "right": 0, "top": 20, "bottom": 10}, data=data, width="100%", height=300, ) ``` ## API Reference ### rx.recharts.Label A Label component in Recharts. #### Props | Prop | Type | Default | Description | | --- | --- | --- | --- | | `view_box` | dict[str, Any] | - | The box of viewing area, which has the shape of {x: someVal, y: someVal, width: someVal, height: someVal}, usually calculated internally. | | `value` | str | - | The value of label, which can be specified by this props or the children of