diff --git a/content/develop/concepts/custom-components/_index.md b/content/develop/concepts/custom-components/_index.md
index fd0c24a3c..0585ba456 100644
--- a/content/develop/concepts/custom-components/_index.md
+++ b/content/develop/concepts/custom-components/_index.md
@@ -1,62 +1,52 @@
---
-title: Components
+title: Custom Components
slug: /develop/concepts/custom-components
-description: Learn how to build and use custom Streamlit components to extend app functionality with third-party Python modules and custom UI elements.
-keywords: custom components, third-party modules, component development, extend functionality, custom UI, component integration, Streamlit components
+description: Learn about Streamlit custom components - powerful extensions that unlock capabilities beyond built-in widgets using web technologies.
+keywords: custom components, component development, extend streamlit, web components, custom widgets, component architecture
---
# Custom Components
-Components are third-party Python modules that extend what's possible with Streamlit.
+Custom Components are powerful extensions for Streamlit that unlock capabilities beyond the built-in widgets. They let you integrate any web technology—from advanced data visualizations to specialized input controls to complete mini-applications—directly into your Streamlit apps.
-## How to use a Component
+## Getting started
-Components are super easy to use:
+
-1. Start by finding the Component you'd like to use. Two great resources for this are:
- - The [Component gallery](https://streamlit.io/components)
- - [This thread](https://discuss.streamlit.io/t/streamlit-components-community-tracker/4634),
- by Fanilo A. from our forums.
+
-2. Install the Component using your favorite Python package manager. This step and all following
- steps are described in your component's instructions.
+
Overview of Custom Components
- For example, to use the fantastic [AgGrid
- Component](https://github.com/PablocFonseca/streamlit-aggrid), you first install it with:
+Learn what custom components are, when to use them, and understand the differences between v1 and v2 approaches.
- ```python
- pip install streamlit-aggrid
- ```
+
-3. In your Python code, import the Component as described in its instructions. For AgGrid, this step
- is:
+
- ```python
- from st_aggrid import AgGrid
- ```
+
Components v2
-4. ...now you're ready to use it! For AgGrid, that's:
+The next generation of custom components with enhanced capabilities, bidirectional communication, and simplified development.
- ```python
- AgGrid(my_dataframe)
- ```
+
-## Making your own Component
+
-If you're interested in making your own component, check out the following resources:
+
Components v1
-- [Create a Component](/develop/concepts/custom-components/create)
-- [Publish a Component](/develop/concepts/custom-components/publish)
-- [Components API](/develop/concepts/custom-components/intro)
-- [Blog post for when we launched Components!](https://blog.streamlit.io/introducing-streamlit-components/)
+The original custom components framework. Learn how to use and build v1 components.
-Alternatively, if you prefer to learn using videos, our engineer Tim Conkling has put together some
-amazing tutorials:
+
-##### Video tutorial, part 1
+
-
+
Publishing Components
-##### Video tutorial, part 2
+Learn how to package and distribute your custom components to the community.
-
+
+
+
+
+## Component gallery
+
+Explore the [Community Component Gallery](https://streamlit.io/components) to discover components built by the Streamlit community.
diff --git a/content/develop/concepts/custom-components/components-v1/_index.md b/content/develop/concepts/custom-components/components-v1/_index.md
new file mode 100644
index 000000000..83f5623d9
--- /dev/null
+++ b/content/develop/concepts/custom-components/components-v1/_index.md
@@ -0,0 +1,62 @@
+---
+title: Components v1
+slug: /develop/concepts/custom-components/components-v1
+description: Learn how to build and use custom Streamlit components to extend app functionality with third-party Python modules and custom UI elements.
+keywords: custom components, third-party modules, component development, extend functionality, custom UI, component integration, Streamlit components
+---
+
+# Custom Components
+
+Components are third-party Python modules that extend what's possible with Streamlit.
+
+## How to use a Component
+
+Components are super easy to use:
+
+1. Start by finding the Component you'd like to use. Two great resources for this are:
+ - The [Component gallery](https://streamlit.io/components)
+ - [This thread](https://discuss.streamlit.io/t/streamlit-components-community-tracker/4634),
+ by Fanilo A. from our forums.
+
+2. Install the Component using your favorite Python package manager. This step and all following
+ steps are described in your component's instructions.
+
+ For example, to use the fantastic [AgGrid
+ Component](https://github.com/PablocFonseca/streamlit-aggrid), you first install it with:
+
+ ```python
+ pip install streamlit-aggrid
+ ```
+
+3. In your Python code, import the Component as described in its instructions. For AgGrid, this step
+ is:
+
+ ```python
+ from st_aggrid import AgGrid
+ ```
+
+4. ...now you're ready to use it! For AgGrid, that's:
+
+ ```python
+ AgGrid(my_dataframe)
+ ```
+
+## Making your own Component
+
+If you're interested in making your own component, check out the following resources:
+
+- [Create a Component](/develop/concepts/custom-components/create)
+- [Publish a Component](/develop/concepts/custom-components/publish)
+- [Components API](/develop/concepts/custom-components/intro)
+- [Blog post for when we launched Components!](https://blog.streamlit.io/introducing-streamlit-components/)
+
+Alternatively, if you prefer to learn using videos, our engineer Tim Conkling has put together some
+amazing tutorials:
+
+##### Video tutorial, part 1
+
+
+
+##### Video tutorial, part 2
+
+
diff --git a/content/develop/concepts/custom-components/components-api.md b/content/develop/concepts/custom-components/components-v1/v1-component-api.md
similarity index 99%
rename from content/develop/concepts/custom-components/components-api.md
rename to content/develop/concepts/custom-components/components-v1/v1-component-api.md
index 6495ae67b..3c989cf28 100644
--- a/content/develop/concepts/custom-components/components-api.md
+++ b/content/develop/concepts/custom-components/components-v1/v1-component-api.md
@@ -1,6 +1,6 @@
---
title: Intro to custom components
-slug: /develop/concepts/custom-components/intro
+slug: /develop/concepts/custom-components/components-v1/intro
description: Learn to develop Streamlit custom components with static and bi-directional communication between Python and JavaScript for extended functionality.
keywords: custom component development, static components, bi-directional components, Python JavaScript communication, component API, component development
---
diff --git a/content/develop/concepts/custom-components/create-component.md b/content/develop/concepts/custom-components/components-v1/v1-component-create.md
similarity index 96%
rename from content/develop/concepts/custom-components/create-component.md
rename to content/develop/concepts/custom-components/components-v1/v1-component-create.md
index 9c4a77328..3ca20016d 100644
--- a/content/develop/concepts/custom-components/create-component.md
+++ b/content/develop/concepts/custom-components/components-v1/v1-component-create.md
@@ -1,6 +1,6 @@
---
title: Create a Component
-slug: /develop/concepts/custom-components/create
+slug: /develop/concepts/custom-components/components-v1/create
description: Step-by-step guide to creating custom Streamlit components from scratch, including setup, development environment, and component structure.
keywords: create component, component development, component setup, development environment, component structure, custom component creation, build components
---
diff --git a/content/develop/concepts/custom-components/limitations.md b/content/develop/concepts/custom-components/components-v1/v1-component-limitations.md
similarity index 96%
rename from content/develop/concepts/custom-components/limitations.md
rename to content/develop/concepts/custom-components/components-v1/v1-component-limitations.md
index f92c4df66..bf0fe8bbd 100644
--- a/content/develop/concepts/custom-components/limitations.md
+++ b/content/develop/concepts/custom-components/components-v1/v1-component-limitations.md
@@ -1,6 +1,6 @@
---
title: Limitations of custom components
-slug: /develop/concepts/custom-components/limitations
+slug: /develop/concepts/custom-components/components-v1/limitations
description: Understand the limitations and constraints of Streamlit custom components including iframe restrictions and differences from base Streamlit functionality.
keywords: component limitations, iframe restrictions, component constraints, custom component issues, component differences, development limitations
---
diff --git a/content/develop/concepts/custom-components/components-v2/_index.md b/content/develop/concepts/custom-components/components-v2/_index.md
new file mode 100644
index 000000000..3da2a2c71
--- /dev/null
+++ b/content/develop/concepts/custom-components/components-v2/_index.md
@@ -0,0 +1,67 @@
+---
+title: Custom components v2
+slug: /develop/concepts/custom-components/components-v2
+description: Learn about Streamlit custom components v2 - the next generation framework with enhanced capabilities, bidirectional communication, and simplified development.
+keywords: custom components v2, next generation components, bidirectional communication, enhanced capabilities, modern component development
+---
+
+# Custom components v2
+
+Components v2 represents a reimagining of how custom components work in Streamlit. It's designed to unlock new capabilities and dramatically simplify the development experience. For command reference, see the [API Reference](/develop/api-reference/custom-components).
+
+## Getting started
+
+
+
+
+
+
Quickstart examples
+
+Get started quickly with practical examples showing interactive buttons, data exchange, and complete component implementations.
+
+
+
+
+
+
Create components
+
+Learn the basics of registering and mounting v2 components with inline development.
+
+
+
+
+
+
State vs triggers
+
+Understand the two communication mechanisms for building interactive components.
+
+
+
+
+
+
Theming & styling
+
+Make your components look great with Streamlit's theme integration and CSS custom properties.
+
+
+
+
+
+
Package-based components
+
+Build complex components with modern frontend tooling, TypeScript, and external dependencies.
+
+
+
+
+
+## Migration from v1 to v2
+
+If you have existing v1 components, check out these migration examples:
+
+- [streamlit-bokeh v2 migration](https://github.com/streamlit/streamlit-bokeh/pull/40)
+- [streamlit-pdf v2 migration](https://github.com/streamlit/streamlit-pdf/pull/25)
+
+## What's next?
+
+Ready to build your first v2 component? Start with the [Quickstart examples](/develop/concepts/custom-components/components-v2/quickstart) to see practical implementations, then dive into the [Create components](/develop/concepts/custom-components/components-v2/create) guide to learn the fundamentals.
diff --git a/content/develop/concepts/custom-components/components-v2/create.md b/content/develop/concepts/custom-components/components-v2/create.md
new file mode 100644
index 000000000..62b88f9fd
--- /dev/null
+++ b/content/develop/concepts/custom-components/components-v2/create.md
@@ -0,0 +1,645 @@
+---
+title: Create custom v2 components
+slug: /develop/concepts/custom-components/components-v2/create
+description: Learn how to create Streamlit custom components v2 with inline development, from basic registration to mounting components with rich interactions.
+keywords: custom components v2, create components, inline components, component registration, component mounting, bidirectional communication
+---
+
+# Create custom v2 components
+
+Components v2 provides a modern, flexible approach to extending Streamlit with custom functionality. This guide will introduce the necessary concepts for creating custom components using the inline development approach. For package-based components, see the [Package-based Components](/develop/concepts/custom-components/components-v2/package-based) guide.
+
+## Two-step component process
+
+Creating and using a custom component involves two distinct steps:
+
+1. **Registration**: Define your component's structure (HTML, CSS, JavaScript).
+2. **Mounting**: Create and display an instance of your component in your app with specific data.
+
+## Step 1: Component registration
+
+Registration is where you define what your component looks like and how it behaves. Use [`st.components.v2.component()`](/develop/api-reference/custom-components/st.components.v2.component) to register a component:
+
+```python
+# Register a component
+my_component = st.components.v2.component(
+ name="my_button",
+ html="",
+ css="button { background: var(--st-primary-color); color: white; }",
+ js="""
+ export default function(component) {
+ const { parentElement, setTriggerValue } = component;
+
+ parentElement.querySelector("button").onclick = () => {
+ setTriggerValue("clicked", true);
+ };
+ }
+ """
+)
+```
+
+### Registration parameters
+
+- `name` (required) is a unique identifier for your component type. This is used internally by Streamlit for each instance to retrieve its HTML, CSS, and JavaScript code. Avoid registering multiple components with the same name.
+- `html` (optional) is the HTML markup for your component. It defines the visual structure of your component. In the previous example, this is a single HTML button element.
+- `css` (optional) is the CSS styling for your component. In the previous example, the CSS sets the button's background color to the primary color from the Streamlit theme and sets the text color to white.
+- `js` (optional) is the JavaScript logic for your component. In the previous example, the JavaScript listens for a click event on the button and sets the `clicked` trigger value to `true`.
+
+For inline component development, the HTML, CSS, and JavaScript code must be raw code as strings. File references are only supported for package-based components.
+
+When you use a path in the `st.components.v2.component()` call, the paths are resolved on the frontend. For a package-based component, Streamlit serves the contents of the package's asset directory, which makes those resources available to your app's frontend and accessible through relative paths. Streamlit doesn't serve an asset directory for inline components. For more information, see [Package-based components](/develop/concepts/custom-components/components-v2/package-based).
+
+
+
+A component must have either `html`, `js`, or both defined! You cannot register a component with only CSS. If you only need to inject CSS, use `st.html()` instead.
+
+
+
+### JavaScript function requirements
+
+Your JavaScript code must export a default function that follows this exact signature:
+
+```javascript
+export default function (component) {
+ // Your component logic here
+
+ // Optional: return cleanup function
+ return () => {
+ // Cleanup logic (remove event listeners, clear timers, etc.)
+ };
+}
+```
+
+The `component` parameter provides these essential properties as documented in the [`ComponentArgs`](/develop/api-reference/custom-components/component-v2-lib-componentargs) type. These properties are typically destructured into local variables for easier access.
+
+```javascript
+export default function (component) {
+ const { name, key, data, parentElement, setStateValue, setTriggerValue } =
+ component;
+
+ // Your component logic here
+}
+```
+
+- `name` (string): Component name from your Python registration.
+- `key` (string): Unique identifier for this component instance. Use this to assist with tracking unique instances of your component in the DOM, especially if your component acts outside of its `parentElement`.
+- `data` (any): All data passed from Python via the `data` parameter. Use this to customize a component instance.
+- `parentElement` (HTMLElement): The DOM element where your component is mounted. Use this to interact with the component's internal DOM elements.
+- `setStateValue` (function): JS function to communicate stateful values to your Python backend. The first argument is the state key name, and the second argument is the value to set.
+- `setTriggerValue` (function): JS function to communicate event-based trigger values to your Python backend. The first argument is the trigger key name, and the second argument is the value to set.
+
+
+
+Don't directly overwrite or replace `parentElement.innerHTML`. If you do, you will overwrite the HTML, CSS, and JavaScript code that was registered with the component. If you need to inject content from `data`, do one of the following things:
+
+- Create a placeholder element within `html` to update.
+- Append children to `parentElement`.
+
+
+
+### Basic registration examples
+
+#### Simple HTML component
+
+In the following examples, we'll register a simple component that displays "Hello, World!" in a heading. We use the primary color from the Streamlit theme for the heading color. For more information about making your components theme-aware, see the [Theming & styling](/develop/concepts/custom-components/components-v2/theming) guide. This example is completed at the end of this guide in the [Complete examples](#simple-html-component-complete-example) section.
+
+```python
+import streamlit as st
+
+hello_component = st.components.v2.component(
+ name="hello_world",
+ html="
Hello, World!
",
+ css="h2 { color: var(--st-primary-color); }"
+)
+```
+
+#### Using files for inline components
+
+For larger components, you can organize your code into separate files. However, for inline component development, you must pass raw HTML, CSS, and JavaScript code to your component. Similar to the [Quickstart examples](/develop/concepts/custom-components/components-v2/quickstart), you can read the files and pass their contents to your inline component. For package-based components, you can pass file references instead. For more information, see [Package-based components](/develop/concepts/custom-components/components-v2/package-based).
+
+```
+my_app/
+├── streamlit_app.py # Entrypoint file
+└── my_component/
+ ├── my_css.css # Component styles
+ ├── my_html.html # Component HTML
+ └── my_js.js # Component JavaScript
+```
+
+```python
+# Load HTML, CSS, and JS from external files
+@st.cache_data
+def load_component_code():
+ with open("my_component/my_css.css", "r") as f:
+ CSS = f.read()
+ with open("my_component/my_html.html", "r") as f:
+ HTML = f.read()
+ with open("my_component/my_js.js", "r") as f:
+ JS = f.read()
+ return HTML, CSS, JS
+
+HTML, CSS, JS = load_component_code()
+
+file_component = st.components.v2.component(
+ name="file_based",
+ html=HTML,
+ css=CSS,
+ js=JS,
+)
+```
+
+#### Interactive component
+
+In the following example, we'll register a component that displays a counter and a button to increment the counter. The counter value is stored in the component's state and is updated when the button is clicked. The component also triggers an event when the button is clicked. The component properties are destructured within the function signature directly. This example is completed at the end of this guide in the [Complete examples](#interactive-counter-complete-example) section.
+
+```python
+import streamlit as st
+
+counter_component = st.components.v2.component(
+ name="counter",
+ html="""
+
+ 0
+
+
+ """,
+ js="""
+ export default function({ parentElement, setStateValue }) {
+ let count = 0;
+ const display = parentElement.querySelector("#count");
+ const button = parentElement.querySelector("#increment");
+
+ button.onclick = () => {
+ count++;
+ display.textContent = count;
+ setStateValue("count", count);
+ };
+ }
+ """
+)
+```
+
+### Sending state and trigger values to Python
+
+You can send state and trigger values to Python by calling `setStateValue()` or `setTriggerValue()` in your JavaScript code. For both functions, the first argument is the state or trigger key name, and the second argument is the value to set.
+
+```javascript
+setStateValue("count", count);
+setTriggerValue("clicked", true);
+```
+
+Both `setStateValue()` and `setTriggerValue()` will trigger a rerun of the script. For each call in JavaScript, the associated callback function in Python will be executed as a prefix to the script run. If you make multiple calls to `setStateValue()` or `setTriggerValue()` within the same event handler, their callbacks will be executed in the order they were called before the script run. However, for `setStateValue()`, the callback function will only be executed if the state value changed as a result of the call. This is described later, in [Event callbacks](#event-callbacks-on_trigger_change-or-on_state_change) section.
+
+## Step 2: Component mounting
+
+After registering your component, you must mount your component in your Streamlit app. This creates a specific instance of the component and is equivalent to calling native Streamlit commands like `st.button()` or `st.text_input()`. This is where you pass data to the component and handle its output.
+
+```python
+import streamlit as st
+
+# Register the component
+my_component = st.components.v2.component(
+ # ... component registration code ...
+)
+
+# Mount the component
+result = my_component(
+ key="unique_instance",
+ data={"initial_value": 42},
+ on_clicked_change=lambda: None)
+)
+```
+
+### Mounting parameters
+
+All mounting parameters are keyword-only and optional. The available parameters are documented in the [`BidiComponentCallable`](/develop/api-reference/custom-components/st.components.v2.types.bidicomponentcallable) class.
+
+#### Component identity (`key`)
+
+Components use the Python `key` parameter in the same manner as widgets. For a detailed overview of keys in widgets, see [Understanding widget behavior](/develop/concepts/architecture/widget-behavior#keys-help-distinguish-widgets-and-access-their-values).
+
+Just like widgets, components have internally computed identities that help Streamlit match component mounting commands to their frontend instances.
+
+- If you pass a key when you mount your component, Streamlit will update the existing frontend elements when other parameters change.
+- If you don't pass a key when you mount your component, Streamlit will create new frontend elements when other parameters change. This will reset the component's state values.
+
+Additionally, you must use keys to disambiguate between otherwise identical instances of the same component.
+
+```python
+# Multiple instances of the same component
+result1 = my_component(key="first_instance")
+result2 = my_component(key="second_instance")
+```
+
+
+
+The `key` property available in the `ComponentArgs` type isn't the same as the Python `key` parameter. On the frontend, the JavaScript `key` is a dynamically generated identifier that is only usable for a specific instance of the component. For example, the JavaScript `key` will change if you mount a component, navigate away from the page, and then navigate back to remount it.
+
+
+
+#### Customizing and updating an instance (`data` and `default`)
+
+In a component mounting command, there are two parameters that you can use to customize and update a component instance: `data` and `default`.
+
+The `data` parameter passes information from Python to your component's frontend. It supports JSON-serializable, Arrow-serializable, and raw bytes data. Commonly this is a single value or a dictionary of values that you retrieve in your JavaScript function.
+
+This code snippet is from the [Rich data exchange](/develop/concepts/custom-components/components-v2/quickstart#rich-data-exchange) quickstart example. It demonstrates passing a dictionary of values to the component's `data` parameter.
+
+```python
+result = chart_component(
+ data={
+ "df": df, # Arrow-serializable dataframe
+ "user_info": {"name": "Alice"}, # JSON-serializable data
+ "image_base64": img_base64 # Image as base64 string
+ }
+)
+```
+
+
+
+DataFrames are automatically serialized using Apache Arrow format, which provides efficient transfer and preserves data types. On the frontend, you can work with the Arrow data directly or convert it to other formats as needed.
+
+
+
+The `default` parameter sets the initial values for component state _in Python_. This is a dictionary where each key is a state name. Each state name has an accompanying callback function passed as a keyword argument named `on__change`. Because `default` only sets the initial value in Python, you must appropriately pass data to the component's `data` parameter to ensure that the component is consistent with its intended initial state.
+
+In general, the `default` parameter is used to avoid a rerun of the script when the component is mounted. If your component immediately calls `setStateValue()` when it's mounted, this can increase the chance of visual flickering. Hence, use the `default` parameter to avoid an unnecessary rerun.
+
+The following example demonstrates how to use the `default` parameter to avoid a rerun of the script when the component is mounted. The simple checkbox is given an initial state of `True`.
+
+```python
+import streamlit as st
+
+simple_component = st.components.v2.component(
+ name="counter",
+ html="""""",
+ js="""
+ export default function({ parentElement, data, setStateValue, key }) {
+ const checkbox = parentElement.querySelector("input[type='checkbox']");
+ const enabled = data.enabled;
+
+ // Initialize checkbox state
+ checkbox.checked = enabled;
+
+ // Update state when checkbox is toggled
+ checkbox.addEventListener("change", () => {
+ setStateValue("enabled", checkbox.checked);
+ });
+ }
+ """
+)
+
+initial_state = True
+
+result = simple_component(
+ data={"enabled": initial_state},
+ default={"enabled": initial_state},
+ on_enabled_change=lambda: None
+)
+result
+```
+
+In the previous example, if the default wasn't set, then the initial state of the `"enabled"` key would be `None`. Thus, the return value would not be consistent with the component's state until the first user interaction triggers the event listener. It's possible to create the same component without using the `default` parameter, but this would make the app rerun unnecessarily when the component is mounted:
+
+```diff
+import streamlit as st
+
+simple_component = st.components.v2.component(
+ name="counter",
+ html="""""",
+ js="""
+ export default function({ parentElement, data, setStateValue, key }) {
+ const checkbox = parentElement.querySelector("input[type='checkbox']");
+ const enabled = data.enabled;
+
+ // Initialize checkbox state
+ checkbox.checked = enabled;
++ setStateValue("enabled", enabled);
+
+ // Update state when checkbox is toggled
+ checkbox.addEventListener("change", () => {
+ setStateValue("enabled", checkbox.checked);
+ });
+ }
+ """
+)
+
+initial_state = False
+
+result = simple_component(
+ data={"enabled": initial_state},
+- default={"enabled": initial_state},
+ on_enabled_change=lambda: None
+)
+result
+```
+
+#### Layout control (`width` and `height`)
+
+To make your component compatible with the Streamlit layout system, you can pass `width` and `height` parameters to your component mounting command. These parameters match the same width and height parameters used in other Streamlit commands. Streamlit wraps your component in a `
` element and updates its `width` and `height` properties so that it behaves like other Streamlit elements.
+
+```python
+result = my_component(
+ width="stretch", # Full width
+ height=400 # Fixed height
+)
+```
+
+On the frontend, it's generally recommended to set your component's CSS to `width: 100%; height: 100%`, since Streamlit will size the `
` wrapper element correctly. If your component needs to know its exact measurements at runtime in JavaScript, you can use a `ResizeObserver` to get that information dynamically.
+
+#### Theming and styling (`isolate_styles`)
+
+Custom Components v2 provides style isolation options to control whether or not to sandbox your component in a shadow root. This is useful to prevent your component's styles from leaking to the rest of the page and to prevent the page's styles from leaking into your component.
+
+```python
+result = my_component(
+ isolate_styles=True # Default behavior uses a shadow root
+)
+```
+
+For more information about theming and styling, see the [Theming & styling](/develop/concepts/custom-components/components-v2/theming) guide.
+
+#### Event callbacks (`on__change` or `on__change`)
+
+For each state and trigger value for your component, you must pass a callback function to the component mounting command. This callback function ensures that its state or trigger value is consistently available in the component's result object.
+
+If you have a trigger named `"click"`, then you have to pass a callback function to the keyword argument `on_click_change`. In general, to create the callback function keyword argument name, prefix your state or trigger name with `on_` and then suffix it with `_change`. These callback functions can be empty (`lambda: None`) or contain your own response logic.
+
+Whenever your JavaScript code calls `setStateValue()` or `setTriggerValue()`, your app will immediately rerun, executing the associated callback as a prefix to the script run. If you make multiple calls to `setStateValue()` or `setTriggerValue()` within the same event handler, their callbacks will be executed before the script run, in the order they were called. However, for `setStateValue()`, the callback function will only be executed if the state value changed as a result of the call.
+
+Continuing the [Interactive component](#interactive-component) example from the previous section, we add a callback function for the `count` state.
+
+```python
+# Define callback function for the count state value
+def handle_count_change():
+ # Called when the component calls setStateValue("count", value)
+ st.toast("Count was updated!")
+
+# Mount the counter component with callback
+result = counter_component(
+ width="content",
+ on_count_change=handle_count_change,
+ key="counter_1"
+)
+```
+
+## Accessing component values
+
+You can access the state and trigger values of a component through the mounting command's return value. Alternatively, if you mounted your component with a key, you can access the component values through Session State.
+
+### Component return value
+
+Components return a [`BidiComponentResult`](/develop/api-reference/custom-components/st.components.v2.types.bidicomponentresult) object that provides access to component state and trigger values. In the previous ("Interactive component") example, you can access the `count` state as `result.count`.
+
+```python
+# Access the current count value
+st.write(f"Current count: {result.count}")
+```
+
+### Component values in Session State
+
+If you mounted your component with a key, you can access the component values through Session State. In the previous ("Interactive component") example, you can equivalently access the `count` state as `st.session_state.counter_1.count`.
+
+```python
+# Access the current count value
+st.write(f"Current count: {st.session_state.counter_1.count}")
+```
+
+### State vs trigger behavior
+
+State and trigger values have different behavior in relation to reruns. State values persist across reruns, while trigger values are transient and reset after each rerun. For more information about state and trigger values, see the [State vs trigger values](/develop/concepts/custom-components/components-v2/state-and-triggers) guide.
+
+## Complete examples
+
+### Simple HTML component complete example
+
+The `hello_component` introduced in a previous section can be completed by just mounting it.
+
+`streamlit_app.py`:
+
+```python
+import streamlit as st
+
+hello_component = st.components.v2.component(
+ name="hello_world",
+ html="
Hello, World!
",
+ css="h2 { color: var(--st-primary-color); }"
+)
+
+hello_component()
+```
+
+To fully make the component theme-compatible, you can add more CSS to use the theme's heading font and weight. Because the theme variables for headings are only available as arrays, this requires some JavaScript logic as well. For more information, see [Theming & styling](/develop/concepts/custom-components/components-v2/theming).
+
+### Interactive counter complete example
+
+For better syntax highlighting, the example is broken down into separate files like the [Quickstart examples](/develop/concepts/custom-components/components-v2/quickstart). The raw code is imported from an `__init__.py` file. The complete code in a single file is provided at the end of each example for easier copying and pasting.
+
+```
+project_directory/
+├── my_component/
+│ ├── __init__.py
+│ ├── my_css.css
+│ ├── my_html.html
+│ └── my_js.js
+└── streamlit_app.py
+```
+
+
+
+```python
+import streamlit as st
+from pathlib import Path
+
+# Get the current file's directory
+_COMPONENT_DIR = Path(__file__).parent
+
+@st.cache_data
+def load_html():
+ with open(_COMPONENT_DIR / "my_html.html", "r") as f:
+ return f.read()
+
+@st.cache_data
+def load_css():
+ with open(_COMPONENT_DIR / "my_css.css", "r") as f:
+ return f.read()
+
+@st.cache_data
+def load_js():
+ with open(_COMPONENT_DIR / "my_js.js", "r") as f:
+ return f.read()
+
+HTML = load_html()
+CSS = load_css()
+JS = load_js()
+```
+
+
+
+The following example includes some minimal CSS to make the component look more Streamlit-like and theme-compatible. For more information about theming and styling, see the [Theming & styling](/develop/concepts/custom-components/components-v2/theming) guide.
+
+`my_component/my_html.html`:
+
+```markup
+
+ 0
+
+
+```
+
+`my_component/my_css.css`:
+
+```css
+.counter {
+ padding: 0.5rem 0.5rem;
+ border: 1px solid var(--st-border-color);
+ border-radius: var(--st-base-radius);
+ font-family: var(--st-font);
+ font-size: var(--st-base-font-size);
+ color: var(--st-text-color);
+}
+#count {
+ padding: 0.75rem;
+}
+#increment {
+ background: var(--st-primary-color);
+ color: white;
+ border: none;
+ border-radius: var(--st-button-radius);
+ padding: 0.25rem 0.5rem;
+ margin-left: 0.25rem;
+}
+#increment:hover {
+ opacity: 0.8;
+}
+```
+
+`my_component/my_js.js`:
+
+```javascript
+export default function ({ parentElement, setStateValue }) {
+ let count = 0;
+ const display = parentElement.querySelector("#count");
+ const button = parentElement.querySelector("#increment");
+
+ button.onclick = () => {
+ count++;
+ display.textContent = count;
+ setStateValue("count", count);
+ };
+}
+```
+
+`streamlit_app.py`:
+
+```python
+import streamlit as st
+from my_component import HTML, CSS, JS
+
+counter_component = st.components.v2.component(
+ name="counter",
+ html=HTML,
+ css=CSS,
+ js=JS
+)
+
+# Define callback function for the count state value
+def handle_count_change():
+ # Called when the component calls setStateValue("count", value)
+ st.toast("Count was updated!")
+
+# Mount the counter component with callback
+result = counter_component(
+ width="content",
+ on_count_change=handle_count_change,
+ key="counter_1"
+)
+
+# Access the current count value
+st.write(f"Current count: {result.count}")
+
+# Access the current count value in Session State
+st.write(f"Current count: {st.session_state.counter_1.count}")
+```
+
+
+
+```python
+import streamlit as st
+
+counter_component = st.components.v2.component(
+ name="counter",
+ html="""
+
+ 0
+
+
+ """,
+ css="""
+ .counter {
+ padding: .5rem .5rem;
+ border: 1px solid var(--st-border-color);
+ border-radius: var(--st-base-radius);
+ font-family: var(--st-font);
+ font-size: var(--st-base-font-size);
+ color: var(--st-text-color);
+ }
+ #count {
+ padding: .75rem;
+ }
+ #increment {
+ background: var(--st-primary-color);
+ color: white;
+ border: none;
+ border-radius: var(--st-button-radius);
+ padding: .25rem .5rem;
+ margin-left: .25rem;
+ }
+ #increment:hover {
+ opacity: 0.8;
+ }
+ """,
+ js="""
+ export default function({ parentElement, setStateValue }) {
+ let count = 0;
+ const display = parentElement.querySelector("#count");
+ const button = parentElement.querySelector("#increment");
+
+ button.onclick = () => {
+ count++;
+ display.textContent = count;
+ setStateValue("count", count);
+ };
+ }
+ """
+)
+
+# Define callback function for the count state value
+def handle_count_change():
+ # Called when the component calls setStateValue("count", value)
+ st.toast("Count was updated!")
+
+# Mount the counter component with callback
+result = counter_component(
+ width="content",
+ on_count_change=handle_count_change,
+ key="counter_1"
+)
+
+# Access the current count value
+st.write(f"Current count: {result.count}")
+
+# Access the current count value in Session State
+st.write(f"Current count: {st.session_state.counter_1.count}")
+```
+
+
+
+## What's next?
+
+Now that you understand the basics of component registration and mounting:
+
+- Learn about [State vs triggers](/develop/concepts/custom-components/v2/state-and-triggers) for advanced component communication.
+- Explore [Theming and styling](/develop/concepts/custom-components/v2/theming) to make your components look great.
+- Discover [Package-based components](/develop/concepts/custom-components/v2/package-based) for complex projects.
+- Check out the [JavaScript API reference](/develop/api-reference/custom-components/) for complete frontend documentation.
diff --git a/content/develop/concepts/custom-components/components-v2/package-based.md b/content/develop/concepts/custom-components/components-v2/package-based.md
new file mode 100644
index 000000000..24d713e10
--- /dev/null
+++ b/content/develop/concepts/custom-components/components-v2/package-based.md
@@ -0,0 +1,744 @@
+---
+title: Package-based components
+slug: /develop/concepts/custom-components/components-v2/package-based
+description: Learn how to build complex Custom Components v2 using package-based development with TypeScript, modern build tools, and external dependencies.
+keywords: custom components v2, package-based components, TypeScript, build tools, Vite, Webpack, pyproject.toml, npm packages, component distribution
+---
+
+# Package-based components
+
+While inline components are perfect for rapid prototyping, package-based components provide the full power of modern frontend development. This approach is ideal for complex components that require TypeScript, external dependencies, build optimization, or distribution as Python packages.
+
+## When to use package-based components
+
+Choose package-based development when you need:
+
+- TypeScript support - Type safety and better developer experience.
+- External dependencies - React, D3, Chart.js, or other npm packages.
+- Build optimization - Code splitting, minification, and bundling.
+- Team development - Proper tooling, testing, and collaboration workflows.
+- Distribution - Publishing components as Python packages on PyPI.
+- Complex logic - Multi-file projects with organized code structure.
+
+## Project structure
+
+A typical package-based component follows this structure:
+
+```
+my-component-package/
+├── pyproject.toml # Top-level package configuration
+└── src/
+ └── my_component/
+ ├── __init__.py # Python package entry point
+ ├── component.py # Component Python API
+ ├── pyproject.toml # Component-specific configuration
+ └── frontend/
+ ├── dist/ # Built frontend assets
+ │ ├── bundle-.js
+ │ └── styles-.css
+ ├── src/ # Frontend source code
+ │ ├── index.ts # Main TypeScript entry
+ │ └── components/
+ ├── package.json # Frontend dependencies
+ ├── tsconfig.json # TypeScript configuration
+ └── vite.config.js # Build tool configuration
+```
+
+## Configuration setup
+
+### Top-level `pyproject.toml`
+
+Configure your Python package distribution. This file is located at the root of your project and is used to configure the package distribution. For more information about the `pyproject.toml` for packaging projects, see the [Python Packaging User Guide](https://packaging.python.org/en/latest/tutorials/packaging-projects/).
+
+#### Explicit package configuration (recommended)
+
+This approach explicitly lists packages and their locations. You need to identify each component module and the necessary assets to serve (frontend components and inner `pyproject.toml` file).
+
+```toml
+[project]
+name = "my_streamlit_component_package"
+version = "0.1.0"
+requires-python = ">=3.10"
+dependencies = ["streamlit>=1.51.0"]
+
+[build-system]
+requires = ["setuptools>=61.0", "wheel"]
+build-backend = "setuptools.build_meta"
+
+# Explicitly list packages and their source directory
+[tool.setuptools]
+packages = ["my_component"] # List each package by name
+package-dir = {"" = "src"} # Look for packages in src/ directory
+include-package-data = true # Include non-Python files
+
+# Specify which files to include in the package
+[tool.setuptools.package-data]
+my_component = ["frontend/dist/**/*", "pyproject.toml"]
+```
+
+#### Alternative: Automatic package discovery
+
+For projects with multiple packages or complex structures, you can use automatic discovery:
+
+```toml
+[project]
+name = "my_streamlit_component_package"
+version = "0.1.0"
+requires-python = ">=3.10"
+dependencies = ["streamlit>=1.51.0"]
+
+[build-system]
+requires = ["setuptools>=61.0", "wheel"]
+build-backend = "setuptools.build_meta"
+
+# Automatically find packages matching a pattern
+[tool.setuptools.packages.find]
+where = ["src"] # Look in src/ directory
+include = ["my_component*"] # Include packages starting with "my_component"
+
+[tool.setuptools]
+include-package-data = true
+
+[tool.setuptools.package-data]
+my_component = ["frontend/dist/**/*", "pyproject.toml"]
+```
+
+### Component-level `pyproject.toml`
+
+Within your component module, you need to register your component and specify the asset directory (`asset_dir`) in the `[tool.streamlit.component.components]` table. The `asset_dir` path is relative to the component's `pyproject.toml` file. All files and subdirectories within this directory will be served by Streamlit.
+
+When you start a Streamlit app, Streamlit scans all installed packages for any Streamlit components. For each installed component, Streamlit serves the contents of its asset directory. This makes it possible to refer to images and other assets within your component's HTML and CSS code. `project.name` should match the name of your package when installed.
+
+```toml
+[project]
+name = "my_streamlit_component_package"
+version = "0.1.0"
+
+# Register your components and the asset directory.
+[[tool.streamlit.component.components]]
+name = "my_component"
+asset_dir = "frontend/dist"
+```
+
+
+
+The `asset_dir` path is relative to the component's `pyproject.toml` file. All files and subdirectories within this directory will be served publicly by Streamlit and won't be protected by any logical restrictions in your app. Don't include sensitive information in your component's asset directory.
+
+
+
+## Frontend development setup
+
+### `package.json` configuration
+
+Set up your frontend dependencies and build scripts:
+
+```json
+{
+ "name": "my-component-frontend",
+ "version": "0.1.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview",
+ "type-check": "tsc --noEmit"
+ },
+ "dependencies": {
+ "@streamlit/component-v2-lib": "^0.1.0"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "typescript": "^5.0.0",
+ "vite": "^5.0.0"
+ }
+}
+```
+
+### TypeScript configuration
+
+Configure TypeScript for optimal development:
+
+```json
+{
+ "compilerOptions": {
+ "target": "ES2020",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "skipLibCheck": true,
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src/**/*"],
+ "exclude": ["node_modules", "dist"]
+}
+```
+
+### Vite build configuration
+
+Configure Vite for optimized builds with hashed filenames:
+
+```javascript
+// vite.config.js
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ build: {
+ outDir: "dist",
+ lib: {
+ entry: "src/index.ts",
+ name: "MyComponent",
+ fileName: (format) =>
+ `bundle-[hash].${format === "es" ? "js" : "umd.js"}`,
+ formats: ["es"],
+ },
+ rollupOptions: {
+ output: {
+ assetFileNames: (assetInfo) => {
+ if (assetInfo.name?.endsWith(".css")) {
+ return "styles-[hash].css";
+ }
+ return "[name]-[hash].[ext]";
+ },
+ },
+ },
+ sourcemap: true,
+ },
+});
+```
+
+## TypeScript component development
+
+### Basic TypeScript component
+
+Create a type-safe component using the official TypeScript library:
+
+```typescript
+// src/index.ts
+import { Component, ComponentState } from "@streamlit/component-v2-lib";
+
+/** The state/trigger values this component maintains */
+interface MyComponentState extends ComponentState {
+ count: number;
+ lastAction: string;
+}
+
+/** The shape of the data passed from Python */
+interface MyComponentData {
+ initialCount: number;
+ label: string;
+ theme: "light" | "dark";
+}
+
+const MyComponent: Component = (
+ component,
+) => {
+ const { data, setStateValue, setTriggerValue, parentElement } = component;
+
+ let count = data.initialCount || 0;
+
+ // Create UI elements
+ const container = document.createElement("div");
+ container.className = "component-container";
+
+ const display = document.createElement("div");
+ display.className = "count-display";
+ display.textContent = `Count: ${count}`;
+
+ const incrementBtn = document.createElement("button");
+ incrementBtn.textContent = `${data.label || "Increment"}`;
+ incrementBtn.className = "increment-btn";
+
+ const resetBtn = document.createElement("button");
+ resetBtn.textContent = "Reset";
+ resetBtn.className = "reset-btn";
+
+ // Assemble UI
+ container.appendChild(display);
+ container.appendChild(incrementBtn);
+ container.appendChild(resetBtn);
+ parentElement.appendChild(container);
+
+ // Apply theme
+ container.setAttribute("data-theme", data.theme || "light");
+
+ // Event handlers with type safety
+ const handleIncrement = (): void => {
+ count++;
+ display.textContent = `Count: ${count}`;
+ setStateValue("count", count);
+ setTriggerValue("lastAction", "increment");
+ };
+
+ const handleReset = (): void => {
+ count = 0;
+ display.textContent = `Count: ${count}`;
+ setStateValue("count", count);
+ setTriggerValue("lastAction", "reset");
+ };
+
+ // Attach event listeners
+ incrementBtn.addEventListener("click", handleIncrement);
+ resetBtn.addEventListener("click", handleReset);
+
+ // Initialize state
+ setStateValue("count", count);
+
+ // Return cleanup function
+ return () => {
+ incrementBtn.removeEventListener("click", handleIncrement);
+ resetBtn.removeEventListener("click", handleReset);
+ };
+};
+
+export default MyComponent;
+```
+
+### Advanced component with external dependencies
+
+Here's an example using Chart.js for data visualization:
+
+```typescript
+// src/chart-component.ts
+import { Component, ComponentState } from "@streamlit/component-v2-lib";
+import { Chart, ChartConfiguration, registerables } from "chart.js";
+
+// Register Chart.js components
+Chart.register(...registerables);
+
+interface ChartComponentState extends ComponentState {
+ selectedDataPoint: number | null;
+}
+
+interface ChartData {
+ labels: string[];
+ datasets: Array<{
+ label: string;
+ data: number[];
+ backgroundColor?: string;
+ borderColor?: string;
+ }>;
+}
+
+interface ChartComponentData {
+ chartData: ChartData;
+ chartType: "line" | "bar" | "pie";
+ title?: string;
+}
+
+const ChartComponent: Component = (
+ component,
+) => {
+ const { data, setStateValue, setTriggerValue, parentElement } = component;
+
+ // Create canvas element
+ const canvas = document.createElement("canvas");
+ canvas.width = 400;
+ canvas.height = 300;
+ parentElement.appendChild(canvas);
+
+ // Chart configuration
+ const config: ChartConfiguration = {
+ type: data.chartType || "line",
+ data: data.chartData,
+ options: {
+ responsive: true,
+ plugins: {
+ title: {
+ display: !!data.title,
+ text: data.title,
+ },
+ legend: {
+ position: "top",
+ },
+ },
+ onClick: (event, elements) => {
+ if (elements.length > 0) {
+ const dataIndex = elements[0].index;
+ setStateValue("selectedDataPoint", dataIndex);
+ setTriggerValue("dataPointClicked", {
+ index: dataIndex,
+ label: data.chartData.labels[dataIndex],
+ value: data.chartData.datasets[0].data[dataIndex],
+ });
+ }
+ },
+ },
+ };
+
+ // Create chart instance
+ const chart = new Chart(canvas, config);
+
+ // Cleanup function
+ return () => {
+ chart.destroy();
+ };
+};
+
+export default ChartComponent;
+```
+
+## Python component API
+
+### Component definition
+
+Create a clean Python API for your component:
+
+```python
+# src/my_component/component.py
+import streamlit as st
+from typing import Dict, Any, Optional, Callable, Union, List
+
+def advanced_counter(
+ initial_value: int = 0,
+ label: str = "Increment",
+ theme: str = "light",
+ key: Optional[str] = None,
+ on_count_change: Optional[Callable] = None,
+ on_lastAction_change: Optional[Callable] = None
+):
+ """
+ Create an advanced counter component with TypeScript frontend.
+
+ Parameters
+ ----------
+ initial_value : int
+ The starting count value (default: 0)
+ label : str
+ The text to display on the increment button (default: "Increment")
+ theme : str
+ The component theme, either "light" or "dark" (default: "light")
+ key : str, optional
+ A unique key for the component instance
+ on_count_change : callable, optional
+ Callback function called when count changes
+ on_lastAction_change : callable, optional
+ Callback function called when an action is triggered
+
+ Returns
+ -------
+ ComponentResult
+ Object with count and lastAction properties
+ """
+
+ # Create the component using glob pattern for hashed builds
+ component = st.components.v2.component(
+ name="advanced_counter",
+ js="bundle-*.js", # Glob pattern matches hashed filename
+ css="styles-*.css", # Glob pattern matches hashed CSS
+ data={
+ "initialCount": initial_value,
+ "label": label,
+ "theme": theme
+ }
+ )
+
+ # Mount the component
+ result = component(
+ key=key,
+ default={"count": initial_value, "lastAction": None},
+ on_count_change=on_count_change,
+ on_lastAction_change=on_lastAction_change
+ )
+
+ return result
+
+def chart_component(
+ chart_data: Dict[str, Any],
+ chart_type: str = "line",
+ title: Optional[str] = None,
+ key: Optional[str] = None,
+ on_selectedDataPoint_change: Optional[Callable] = None,
+ on_dataPointClicked_change: Optional[Callable] = None
+):
+ """
+ Create an interactive chart component using Chart.js.
+
+ Parameters
+ ----------
+ chart_data : dict
+ Chart data in Chart.js format with labels and datasets
+ chart_type : str
+ Type of chart: "line", "bar", or "pie" (default: "line")
+ title : str, optional
+ Chart title to display
+ key : str, optional
+ A unique key for the component instance
+ on_selectedDataPoint_change : callable, optional
+ Callback when a data point is selected
+ on_dataPointClicked_change : callable, optional
+ Callback when a data point is clicked
+
+ Returns
+ -------
+ ComponentResult
+ Object with selectedDataPoint and dataPointClicked properties
+ """
+
+ component = st.components.v2.component(
+ name="chart_component",
+ js="chart-bundle-*.js",
+ css="chart-styles-*.css",
+ data={
+ "chartData": chart_data,
+ "chartType": chart_type,
+ "title": title
+ }
+ )
+
+ result = component(
+ key=key,
+ default={"selectedDataPoint": None},
+ on_selectedDataPoint_change=on_selectedDataPoint_change,
+ on_dataPointClicked_change=on_dataPointClicked_change
+ )
+
+ return result
+```
+
+### Package entry point
+
+Create a clean package interface:
+
+```python
+# src/my_component/__init__.py
+"""
+My Streamlit Component Package
+
+A collection of advanced custom components built with TypeScript and modern tooling.
+"""
+
+from .component import advanced_counter, chart_component
+
+__version__ = "0.1.0"
+__all__ = ["advanced_counter", "chart_component"]
+```
+
+## Glob pattern support
+
+Package-based components support glob patterns for referencing build outputs with hashed filenames:
+
+### Why use glob patterns?
+
+Modern build tools like Vite and Webpack generate hashed filenames for cache busting:
+
+```
+frontend/dist/
+├── bundle-a1b2c3d4.js # Hashed JavaScript bundle
+├── styles-e5f6g7h8.css # Hashed CSS file
+└── assets/
+ └── logo-i9j0k1l2.png # Hashed assets
+```
+
+### Glob resolution rules
+
+1. Pattern matching: `bundle-*.js` matches `bundle-a1b2c3d4.js`
+2. Single file requirement: Pattern must resolve to exactly one file
+3. Security: Matched files must be within the `asset_dir`
+4. Relative paths: Patterns are resolved relative to `asset_dir`
+
+### Example usage
+
+```python
+# These glob patterns work with hashed build outputs
+component = st.components.v2.component(
+ name="my_component",
+ js="bundle-*.js", # Matches bundle-.js
+ css="styles-*.css", # Matches styles-.css
+ data={"message": "Hello"}
+)
+```
+
+
+
+**Error Handling**: If a glob pattern matches zero files or multiple files, Streamlit will raise a clear error message to help you debug the issue.
+
+
+
+## Development workflow
+
+### Development mode
+
+During development, use Vite's dev server for hot reloading:
+
+```bash
+# Terminal 1: Start frontend dev server
+cd src/my_component/frontend
+npm run dev
+
+# Terminal 2: Run Streamlit app
+streamlit run app.py
+```
+
+For development, temporarily use the dev server URL:
+
+```python
+# Development mode (temporary)
+component = st.components.v2.component(
+ name="my_component",
+ js="http://localhost:5173/src/index.ts", # Dev server URL
+ data={"message": "Hello"}
+)
+```
+
+### Build for production
+
+Build optimized assets for production:
+
+```bash
+cd src/my_component/frontend
+npm run build
+```
+
+This generates hashed files in the `dist/` directory that your glob patterns will match.
+
+### Testing the package
+
+Test your component locally before publishing:
+
+```python
+# app.py - Test your component
+import streamlit as st
+from my_component import advanced_counter, chart_component
+
+st.title("Component Testing")
+
+# Test the counter
+counter_result = advanced_counter(
+ initial_value=5,
+ label="Click me!",
+ theme="dark",
+ key="test_counter"
+)
+
+st.write(f"Count: {counter_result.count}")
+if counter_result.lastAction:
+ st.write(f"Last action: {counter_result.lastAction}")
+
+# Test the chart
+chart_data = {
+ "labels": ["Jan", "Feb", "Mar", "Apr", "May"],
+ "datasets": [{
+ "label": "Sales",
+ "data": [12, 19, 3, 5, 2],
+ "backgroundColor": "rgba(54, 162, 235, 0.2)",
+ "borderColor": "rgba(54, 162, 235, 1)"
+ }]
+}
+
+chart_result = chart_component(
+ chart_data=chart_data,
+ chart_type="bar",
+ title="Monthly Sales",
+ key="test_chart"
+)
+
+if chart_result.selectedDataPoint is not None:
+ st.write(f"Selected data point: {chart_result.selectedDataPoint}")
+```
+
+## Publishing your package
+
+### Build the distribution
+
+```bash
+# Install build tools
+pip install build twine
+
+# Build the package
+python -m build
+```
+
+### Upload to PyPI
+
+```bash
+# Upload to Test PyPI first
+python -m twine upload --repository testpypi dist/*
+
+# After testing, upload to PyPI
+python -m twine upload dist/*
+```
+
+### Installation and usage
+
+Users can then install and use your component:
+
+```bash
+pip install my-streamlit-component-package
+```
+
+```python
+import streamlit as st
+from my_streamlit_component_package import advanced_counter
+
+result = advanced_counter(
+ initial_value=10,
+ label="Increment Counter",
+ theme="dark"
+)
+
+st.write(f"Current count: {result.count}")
+```
+
+## Best practices
+
+### Type safety
+
+Always use TypeScript interfaces for better development experience:
+
+```typescript
+interface ComponentProps {
+ data: MyComponentData;
+ setStateValue: (key: string, value: any) => void;
+ setTriggerValue: (key: string, value: any) => void;
+ parentElement: HTMLElement;
+}
+```
+
+### Error handling
+
+Implement robust error handling in both TypeScript and Python:
+
+```typescript
+// TypeScript error handling
+export default function (component) {
+ try {
+ // Component logic here
+ return () => {
+ // Cleanup logic
+ };
+ } catch (error) {
+ console.error("Component error:", error);
+ component.parentElement.innerHTML = `
Component failed to load
`;
+ }
+}
+```
+
+### Performance optimization
+
+- Use code splitting for large dependencies
+- Implement lazy loading for heavy components
+- Optimize bundle sizes with tree shaking
+
+### Documentation
+
+Provide comprehensive documentation:
+
+- TypeScript interfaces for all data shapes
+- Python docstrings with parameter descriptions
+- Usage examples and tutorials
+- Migration guides for updates
+
+## What's next?
+
+Now that you understand package-based components:
+
+- Learn about [State vs triggers](/develop/concepts/custom-components/v2/state-and-triggers) for interactive functionality.
+- Explore [Theming and styling](/develop/concepts/custom-components/v2/theming) for beautiful components.
+- Check out [Publishing components](/develop/concepts/custom-components/publish) for distribution strategies.
diff --git a/content/develop/concepts/custom-components/components-v2/quickstart.md b/content/develop/concepts/custom-components/components-v2/quickstart.md
new file mode 100644
index 000000000..68fec8634
--- /dev/null
+++ b/content/develop/concepts/custom-components/components-v2/quickstart.md
@@ -0,0 +1,980 @@
+---
+title: Quickstart examples
+slug: /develop/concepts/custom-components/components-v2/quickstart
+description: Get started quickly with Custom Components v2 through practical examples showing interactive buttons, data exchange, and complete component implementations.
+keywords: custom components v2, quickstart, examples, interactive components, data exchange, component examples, getting started
+---
+
+# Quickstart examples
+
+Get started with custom components v2 through these practical examples that demonstrate the key features and capabilities.
+
+## Two-step component process
+
+Creating and using a custom component involves two distinct steps:
+
+1. Register your component to define its structure (HTML, CSS, JavaScript).
+ - Register a component with [`st.components.v2.component()`](/develop/api-reference/custom-components/st.components.v2.component).
+ - Optional: To enable bidirectional communication, within your component's JavaScript function, communicate with Python by calling `setStateValue()` or `setTriggerValue()`. These are properties of the [`ComponentArgs`](/develop/api-reference/custom-components/component-v2-lib-componentargs) object passed to your function.
+ - Optional: To make your component theme-aware, within your component's CSS, style your component with Streamlit's [theme variables](/develop/concepts/custom-components/components-v2/theming#using-css-custom-properties).
+
+2. Mount your component to create a specific instance in your app.
+ - Use your component command, which inherits from the [`BidiComponentCallable`](/develop/api-reference/custom-components/st.components.v2.types.bidicomponentcallable) class.
+
+For more information, see [Create custom v2 components](/develop/concepts/custom-components/components-v2/create).
+
+## Simple interactive button
+
+This example shows the basics of creating an interactive component with bidirectional communication. It shows the following key concepts:
+
+- Component registration with HTML, CSS, and JavaScript.
+- Trigger values using `setTriggerValue()`.
+- Callback functions with the `on__change` naming pattern.
+- Mounting a component with its command created from registration.
+
+```python
+import streamlit as st
+
+if "click_count" not in st.session_state:
+ st.session_state.click_count = 0
+
+def handle_button_click():
+ st.session_state.click_count += 1
+
+my_component = st.components.v2.component(
+ "interactive_button",
+ html="""""",
+ css="""
+ button {
+ border: none;
+ padding: .5rem;
+ border-radius: var(--st-button-radius);
+ background-color: var(--st-primary-color);
+ color: white;
+ }
+ """,
+ js="""
+ export default function(component) {
+ const { setTriggerValue, parentElement } = component;
+
+ parentElement.querySelector("button").onclick = () => {
+ setTriggerValue("action", "button_clicked");
+ };
+ }
+ """,
+)
+
+result = my_component(on_action_change=handle_button_click)
+
+if result.action:
+ st.write(f"Button clicked! Total clicks: {st.session_state.click_count}")
+```
+
+For inline component development, you must pass raw HTML, CSS, and JavaScript code to your component. Package-based components allow you to pass file references to your component. If you want to use files for an inline component, you'll need to read them into strings. The previous example is equivalent to the following:
+
+```
+project_directory/
+├── my_component/
+│ ├── __init__.py
+│ ├── my_css.css
+│ ├── my_html.html
+│ └── my_js.js
+└── streamlit_app.py
+```
+
+
+
+```python
+import streamlit as st
+from pathlib import Path
+
+# Get the current file's directory
+_COMPONENT_DIR = Path(__file__).parent
+
+@st.cache_data
+def load_html():
+ with open(_COMPONENT_DIR / "my_html.html", "r") as f:
+ return f.read()
+
+@st.cache_data
+def load_css():
+ with open(_COMPONENT_DIR / "my_css.css", "r") as f:
+ return f.read()
+
+@st.cache_data
+def load_js():
+ with open(_COMPONENT_DIR / "my_js.js", "r") as f:
+ return f.read()
+
+HTML = load_html()
+CSS = load_css()
+JS = load_js()
+```
+
+
+
+
+
+```css
+button {
+ border: none;
+ padding: 0.5rem;
+ border-radius: var(--st-button-radius);
+ background-color: var(--st-primary-color);
+ color: white;
+}
+```
+
+
+
+
+
+```markup
+
+```
+
+
+
+
+
+```javascript
+export default function (component) {
+ const { setTriggerValue, parentElement } = component;
+
+ parentElement.querySelector("button").onclick = () => {
+ setTriggerValue("action", "button_clicked");
+ };
+}
+```
+
+
+
+
+
+```python
+import streamlit as st
+from my_component import HTML, CSS, JS
+
+if "click_count" not in st.session_state:
+ st.session_state.click_count = 0
+
+def handle_button_click():
+ st.session_state.click_count += 1
+
+my_component = st.components.v2.component(
+ "interactive_button",
+ html=HTML,
+ css=CSS,
+ js=JS,
+)
+
+result = my_component(on_action_change=handle_button_click)
+
+if result.action:
+ st.write(f"Button clicked! Total clicks: {st.session_state.click_count}")
+```
+
+
+
+The remaining examples on this page will use this file structure for easier viewing of the embedded code blocks. The complete code is provided at the end of each example for easier copying and pasting.
+
+
+
+To avoid repeat warnings about re-registering the component, you can register your component in another module and import it. The standalone examples on this page are simple enough that this issue isn't apparent, but with more complex apps and components, this can be a nuisance.
+
+
+
+## Rich data exchange
+
+This example shows how to pass different data types to your component. It shows the following key concepts:
+
+- Automatic dataframe conversion to Arrow format.
+- Passing JSON data.
+- Passing an image as a base64 string.
+- Accessing data in JavaScript via the destructured `data` property.
+
+`my_component/my_html.html`:
+
+```markup
+
+
+ `;
+ }
+ """,
+)
+
+result = chart_component(
+ data={
+ "df": df, # Arrow-serializable dataframe
+ "user_info": {"name": "Alice"}, # JSON-serializable data
+ "image_base64": img_base64 # Image as base64 string
+ }
+)
+```
+
+
+
+## Complete interactive counter
+
+This comprehensive example demonstrates both state and trigger values. It shows the following key concepts:
+
+- Using state and trigger values together in one component.
+- Using CSS custom properties to style the component.
+- Bidirectional communication between Python and JavaScript.
+- Multiple event handlers.
+- Cleanup functions for proper resource management
+
+`my_component/my_html.html`:
+
+```markup
+
+ """,
+ css="""
+ .form-container {
+ padding: 1rem;
+ border: 1px solid var(--st-border-color);
+ border-radius: var(--st-base-radius);
+ box-sizing: border-box;
+ }
+ h3 {
+ font-size: var(--st-heading-font-size-h3, inherit);
+ font-weight: var(--st-heading-font-weight-h3, inherit);
+ margin: 0;
+ }
+ input,
+ textarea {
+ width: 100%;
+ padding: 0.5rem;
+ margin: 0.5rem 0;
+ background: var(--st-secondary-background-color);
+ border: 1px solid transparent;
+ border-radius: var(--st-base-radius);
+ box-sizing: border-box;
+ font-size: inherit;
+ font-family: inherit;
+ }
+ input:focus,
+ textarea:focus {
+ outline: none;
+ border-color: var(--st-primary-color);
+ }
+ textarea {
+ height: 5rem;
+ resize: vertical;
+ }
+ .form-actions {
+ display: flex;
+ gap: 1rem;
+ margin-top: 0.75rem;
+ }
+ button {
+ padding: 0.5rem 1rem;
+ border-radius: var(--st-button-radius);
+ border: 1px solid transparent;
+ font-size: inherit;
+ font-family: inherit;
+ }
+ button[type="submit"] {
+ background: var(--st-primary-color);
+ color: white;
+ }
+ button[type="button"] {
+ border: 1px solid var(--st-border-color);
+ background: var(--st-primary-background-color);
+ color: var(--st-text-color);
+ }
+ button:hover {
+ opacity: 0.9;
+ border-color: var(--st-primary-color);
+ }
+ #status {
+ margin-top: 0.5rem;
+ }
+ """,
+ js="""
+ export default function ({
+ parentElement,
+ setStateValue,
+ setTriggerValue,
+ data,
+ }) {
+ const form = parentElement.querySelector("#contact-form");
+ const nameInput = parentElement.querySelector("#name");
+ const emailInput = parentElement.querySelector("#email");
+ const messageInput = parentElement.querySelector("#message");
+ const saveDraftBtn = parentElement.querySelector("#save-draft");
+ const status = parentElement.querySelector("#status");
+
+ // Register custom CSS variables with third values from --st-heading-font-sizes and --st-heading-font-weights
+ requestAnimationFrame(() => {
+ const container = parentElement.querySelector(".form-container");
+ const headingSizes = getComputedStyle(form)
+ .getPropertyValue("--st-heading-font-sizes")
+ .trim();
+ const headingWeights = getComputedStyle(form)
+ .getPropertyValue("--st-heading-font-weights")
+ .trim();
+ const sizes = headingSizes.split(",").map((s) => s.trim());
+ const weights = headingWeights.split(",").map((s) => s.trim());
+ if (sizes[2] && container) {
+ container.style.setProperty("--st-heading-font-size-h3", sizes[2]);
+ }
+ if (weights[2] && container) {
+ container.style.setProperty("--st-heading-font-weight-h3", weights[2]);
+ }
+ });
+
+ // Load draft if available
+ const loadDraft = (draft) => {
+ nameInput.value = draft.name || "";
+ emailInput.value = draft.email || "";
+ messageInput.value = draft.message || "";
+ };
+
+ loadDraft(data?.draft || {});
+
+ // Save draft
+ const saveDraft = () => {
+ setStateValue("draft", {
+ name: nameInput.value,
+ email: emailInput.value,
+ message: messageInput.value,
+ });
+ setTriggerValue("action", "save_draft");
+ status.textContent = "Draft saved!";
+ status.style.color = "var(--st-green-color)";
+ setTimeout(() => (status.textContent = ""), 2000);
+ };
+
+ // Submit form
+ const submitForm = (e) => {
+ e.preventDefault();
+
+ if (!nameInput.value || !emailInput.value || !messageInput.value) {
+ status.textContent = "Please fill all fields";
+ status.style.color = "var(--st-red-color)";
+ return;
+ }
+
+ status.textContent = "Message sent!";
+ status.style.color = "var(--st-blue-color)";
+ setTimeout(() => (status.textContent = ""), 2000);
+ setTriggerValue("submit", {
+ name: nameInput.value,
+ email: emailInput.value,
+ message: messageInput.value,
+ });
+ loadDraft({});
+ setStateValue("draft", {});
+ };
+
+ // Event listeners - only update on button clicks
+ saveDraftBtn.addEventListener("click", saveDraft);
+ form.addEventListener("submit", submitForm);
+
+ return () => {
+ saveDraftBtn.removeEventListener("click", saveDraft);
+ form.removeEventListener("submit", submitForm);
+ };
+ }
+ """
+)
+
+# Handle form actions
+def handle_form_action():
+ # Process submission
+ # if submission_failed:
+ # submission = st.session_state.message_form.submit
+ # st.session_state.message_form.draft=submission
+ pass
+
+# Use the component
+form_state = st.session_state.get("message_form", {})
+result = form_component(
+ data={"draft": form_state.get("draft", {})},
+ default={"draft": form_state.get("draft", {})},
+ on_draft_change=lambda: None,
+ on_submit_change=handle_form_action,
+ key="message_form"
+)
+
+if result.submit:
+ st.write("Message Submitted:")
+ result.submit
+else:
+ st.write("Current Draft:")
+ result.draft
+```
+
+
+
+## What's next?
+
+Now that you've seen these examples:
+
+- Learn the fundamentals in [Create components](/develop/concepts/custom-components/components-v2/create).
+- Understand [State vs triggers](/develop/concepts/custom-components/components-v2/state-and-triggers) for advanced interactions.
+- Explore [Theming and styling](/develop/concepts/custom-components/components-v2/theming) to make beautiful components.
+- Build complex projects with [Package-based components](/develop/concepts/custom-components/components-v2/package-based).
diff --git a/content/develop/concepts/custom-components/components-v2/state-and-triggers.md b/content/develop/concepts/custom-components/components-v2/state-and-triggers.md
new file mode 100644
index 000000000..9d758bc2e
--- /dev/null
+++ b/content/develop/concepts/custom-components/components-v2/state-and-triggers.md
@@ -0,0 +1,1547 @@
+---
+title: State vs trigger values
+slug: /develop/concepts/custom-components/components-v2/state-and-triggers
+description: Learn the fundamental difference between state and trigger values in Custom Components v2, and when to use each approach for bidirectional communication.
+keywords: custom components v2, state values, trigger values, bidirectional communication, component events, callback functions, setStateValue, setTriggerValue
+---
+
+# State versus trigger values
+
+Custom components v2 provides two distinct mechanisms for frontend-to-backend communication, each designed for different use cases. Understanding when to use state values versus trigger values is crucial for building effective interactive components.
+
+## Two communication patterns
+
+### State values: Persistent data
+
+**Purpose**: Represent the current "state" of your component that persists across reruns.
+
+**When to use**: For values that represent ongoing component state like current selections, input values, or configuration settings.
+
+State values have the following behavior:
+
+- Persist across Streamlit reruns.
+- Accessible via direct property access on the result object and through Session State (when mounted with a key).
+- Updated using `setStateValue(key, value)` in JavaScript.
+
+### Trigger values: Event-based communication
+
+**Purpose**: Signal one-time events or user interactions.
+
+**When to use**: For user actions like clicks, form submissions, or other discrete events.
+
+Trigger values have the following behavior:
+
+- Are transient and only available for one script rerun.
+- Reset to `None` after the rerun completes.
+- Accessible via direct property access on the result object and through Session State (when mounted with a key).
+- Updated using `setTriggerValue(key, value)` in JavaScript.
+
+## Differences at a glance
+
+| Aspect | State values | Trigger values |
+| :------------------ | :-------------------------------------------- | :--------------------------------------- |
+| Persistence | Maintained across reruns | Only available for one rerun |
+| Use case | Current component state | One-time events/actions |
+| JavaScript function | `setStateValue(key, value)` | `setTriggerValue(key, value)` |
+| Callback execution | Only if `setStateValue()` _changed_ the value | Every time `setTriggerValue()` is called |
+
+## State values in practice: Radial menu component
+
+State values are perfect for tracking the ongoing state of your component. Here's a practical example that demonstrates using a state value to track a selection. The following code creates a radial menu component that allows the user to select a food item from a list of options. When the user selects an item, the component updates the state value with `setStateValue("selection", currentSelection)`. You can expand or collapse the each code block as needed. For emphasis, the JavaScript and example app code are expanded by default.
+
+For simplicity, this compoenent assumes it will always have six options in its menu, but with a little more code, you can generalize it accept an arbitrary number of items. The complete code provided at the end of this section demonstrates a generalized version that accepts an arbitrary number of items.
+
+For this example, the component is registered in an imported module.
+
+```
+project_directory/
+├── radial_menu_component/
+│ ├── __init__.py
+│ ├── menu.css
+│ ├── menu.html
+│ └── menu.js
+└── streamlit_app.py
+```
+
+### Radial menu component registration
+
+
+
+```python
+from pathlib import Path
+import streamlit as st
+
+component_dir = Path(__file__).parent
+
+
+@st.cache_data
+def load_component_code():
+ with open(component_dir / "menu.css", "r") as f:
+ CSS = f.read()
+ with open(component_dir / "menu.html", "r") as f:
+ HTML = f.read()
+ with open(component_dir / "menu.js", "r") as f:
+ JS = f.read()
+ return HTML, CSS, JS
+
+
+HTML, CSS, JS = load_component_code()
+
+radial_menu = st.components.v2.component(
+ name="radial_menu",
+ html=HTML,
+ css=CSS,
+ js=JS,
+)
+```
+
+
+
+### Radial menu HTML code
+
+
+
+```markup
+
",
+ css=".my-style { color: red; }", # Won't affect other elements
+ isolate_styles=True # Default
+)
+```
+
+Benefits of isolation:
+
+- Component styles won't leak to the rest of the page.
+- Page styles won't interfere with your component.
+- Safer for third-party components.
+
+### Non-isolated styles
+
+If you want your component's style to affect the rest of the page, you can set `isolate_styles=False`. This is uncommon.
+
+```python
+# Styles can affect the page
+non_isolated_component = st.components.v2.component(
+ name="non_isolated",
+ html="
Content with inheritance
",
+ css=".inherits-styles { font-family: inherit; }", # Inherits page fonts
+ isolate_styles=False
+)
+```
+
+## Responsive design
+
+Create components that work well across different screen sizes. This makes your component more accessible and compatible with the Streamlit layout system. The following example uses `@media (max-width: 768px)` to create a responsive grid layout that adapts when the screen width is less than 768px.
+
+```python
+import streamlit as st
+
+responsive_component = st.components.v2.component(
+ name="responsive_layout",
+ html="""
+
+
Item 1
+
Item 2
+
Item 3
+
Item 4
+
+ """,
+ css="""
+ .responsive-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 1rem;
+ padding: 1rem;
+ font-family: var(--st-font);
+ }
+
+ .grid-item {
+ background: var(--st-secondary-background-color);
+ border: 1px solid var(--st-border-color);
+ border-radius: var(--st-base-radius);
+ padding: 1.25rem;
+ text-align: center;
+ color: var(--st-text-color);
+ transition: transform 0.2s;
+ }
+
+ .grid-item:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 0.25rem 0.5rem rgba(0, 0, 0, 0.1);
+ }
+
+ /* Mobile-specific styles */
+ @media (max-width: 768px) {
+ .responsive-grid {
+ grid-template-columns: 1fr;
+ gap: 0.75rem;
+ padding: 0.75rem;
+ }
+
+ .grid-item {
+ padding: 1rem;
+ }
+ }
+ """
+)
+
+responsive_component(key="responsive_example")
+```
+
+## Best practices
+
+### Always use theme variables
+
+Instead of hardcoding colors, always use Streamlit's theme variables:
+
+```css
+/* Don't do this */
+.my-component {
+ color: #262730;
+ background: #ffffff;
+}
+
+/* Do this instead */
+.my-component {
+ color: var(--st-text-color);
+ background: var(--st-background-color);
+}
+```
+
+### Test in different themes
+
+Always test your components in both light and dark base themes. Preferably, test your component with a custom theme as well, especially using different font sizes.
+
+### Use semantic color names
+
+Choose colors from the basic color palette based on their semantic meaning. Each color in the basic color palette has a text and background variation, in addition to its base color.
+
+```css
+/* Good - semantic usage */
+.error-message {
+ color: var(--st-red-text-color);
+ background: var(--st-red-background-color);
+}
+
+.success-indicator {
+ color: var(--st-green-color);
+}
+```
+
+### Respect accessibility
+
+Streamlit's theme colors are designed with accessibility in mind. Maintain proper contrast ratios when creating custom color combinations.
+
+## What's next?
+
+Now that you understand theming and styling:
+
+- Explore [Package-based components](/develop/concepts/custom-components/v2/package-based) for advanced development workflows.
+- Learn about [State vs triggers](/develop/concepts/custom-components/v2/state-and-triggers) for interactive components.
+- Check out the [Create components](/develop/concepts/custom-components/v2/create) guide for more examples.
diff --git a/content/develop/concepts/custom-components/overview.md b/content/develop/concepts/custom-components/overview.md
new file mode 100644
index 000000000..6b912c483
--- /dev/null
+++ b/content/develop/concepts/custom-components/overview.md
@@ -0,0 +1,53 @@
+---
+title: Overview of custom components
+slug: /develop/concepts/custom-components/overview
+description: Understand what Streamlit custom components are, when to use them, and compare the v1 and v2 approaches for building interactive extensions.
+keywords: custom components overview, component comparison, v1 vs v2, component capabilities, when to use components, component architecture
+---
+
+# Overview of custom components
+
+Custom components are like plugins for Streamlit that unlock capabilities beyond the built-in features. They let you integrate any web technology directly into your Streamlit app. You can create single-use custom components in your app, or package a custom component to share.
+
+Custom components can help you in the following situations:
+
+- **Built-in widgets don't meet your needs** - You need functionality that Streamlit's standard widgets can't provide.
+- **You want to integrate existing web tools** - You have JavaScript libraries or web components you want to use.
+- **You need complex interactions** - Your use case requires bidirectional communication or complex state management.
+- **You're building reusable functionality** - You want to package and share functionality across multiple apps or with the community.
+
+## Components v2 (recommended)
+
+Custom components v2 is the modern, recommended approach for building custom components in Streamlit. It represents a complete reimagining of how components work. It's designed to unlock new capabilities and dramatically simplify development.
+
+Custom components v2 include the following benefits:
+
+- **No iframe isolation** - Components are part of the Streamlit page, not isolated sandboxes.
+- **Multiple callback support** - You can pass multiple callbacks to a component for rich interactions.
+- **Stateful and event-based values** - Components have both state and event-based trigger values.
+- **Rich data exchange** - Components automatically handle JSON and dataframe (Apache Arrow) serialization.
+- **Simpler development and rapid prototyping** - You can provide HTML, CSS, and JavaScript directly from Python or build a package with TypeScript.
+- **Bidirectional communication** - Convenient utilities make bidirectional communication easy.
+- **Seamless Theme Integration** - Components automatically inherit Streamlit's theme through CSS custom properties.
+
+## Components v1 (legacy)
+
+Components v1 is the original framework that has been stable and widely used since 2020. While components v2 is now the recommended approach, components v1 remains supported for existing components.
+
+V1 components have the following key differences from v2 components:
+
+- **Iframe isolation** - Components run in isolated iframes for security.
+- **Primarily unidirectional communication** - The API is less optimatized for bidirectional communication.
+- **Mature ecosystem** - Many existing components and templates use the v1 architecture.
+
+## Comparing components v1 and v2
+
+| Feature | Components v2 **Recommended** | Components v1 |
+| -------------------- | ------------------------------------------ | ------------------------ |
+| **Communication** | Full bidirectional with multiple callbacks | Primarily unidirectional |
+| **Isolation** | Integrated with page | Iframe-based |
+| **Data exchange** | Rich formats (JSON, Arrow, bytes) | Basic JSON |
+| **Development** | Inline or package-based | Template-based |
+| **State management** | Full state and trigger support | Limited |
+| **Prototyping** | Immediate with inline approach | Requires setup |
+| **Best for** | New projects and modern features | Existing components |
diff --git a/content/develop/concepts/custom-components/publish-component.md b/content/develop/concepts/custom-components/publish.md
similarity index 100%
rename from content/develop/concepts/custom-components/publish-component.md
rename to content/develop/concepts/custom-components/publish.md
diff --git a/content/menu.md b/content/menu.md
index 0569cc83e..d3540958e 100644
--- a/content/menu.md
+++ b/content/menu.md
@@ -98,14 +98,30 @@ site_menu:
url: /develop/concepts/connections/security-reminders
- category: Develop / Concepts / Custom components
url: /develop/concepts/custom-components
- - category: Develop / Concepts / Custom components / Intro to custom components
- url: /develop/concepts/custom-components/intro
- - category: Develop / Concepts / Custom components / Create a Component
- url: /develop/concepts/custom-components/create
- - category: Develop / Concepts / Custom components / Publish a Component
+ - category: Develop / Concepts / Custom components / Overview
+ url: /develop/concepts/custom-components/overview
+ - category: Develop / Concepts / Custom components / Components v2
+ url: /develop/concepts/custom-components/components-v2
+ - category: Develop / Concepts / Custom components / Components v2 / Quickstart examples
+ url: /develop/concepts/custom-components/components-v2/quickstart
+ - category: Develop / Concepts / Custom components / Components v2 / Create components
+ url: /develop/concepts/custom-components/components-v2/create
+ - category: Develop / Concepts / Custom components / Components v2 / State vs trigger values
+ url: /develop/concepts/custom-components/components-v2/state-and-triggers
+ - category: Develop / Concepts / Custom components / Components v2 / Theming and styling
+ url: /develop/concepts/custom-components/components-v2/theming
+ - category: Develop / Concepts / Custom components / Components v2 / Package-based components
+ url: /develop/concepts/custom-components/components-v2/package-based
+ - category: Develop / Concepts / Custom components / Components v1
+ url: /develop/concepts/custom-components/components-v1
+ - category: Develop / Concepts / Custom components / Components v1 / Intro to v1 components
+ url: /develop/concepts/custom-components/components-v1/intro
+ - category: Develop / Concepts / Custom components / Components v1 / Create a component
+ url: /develop/concepts/custom-components/components-v1/create
+ - category: Develop / Concepts / Custom components / Components v1 / Limitations
+ url: /develop/concepts/custom-components/components-v1/limitations
+ - category: Develop / Concepts / Custom components / Publish a component
url: /develop/concepts/custom-components/publish
- - category: Develop / Concepts / Custom components / Limitations
- url: /develop/concepts/custom-components/limitations
- category: Develop / Concepts / Custom components / Component gallery
url: https://streamlit.io/components
- category: Develop / Concepts / Configuration and theming
diff --git a/public/_redirects b/public/_redirects
index f1141914c..6c7582001 100644
--- a/public/_redirects
+++ b/public/_redirects
@@ -43,14 +43,14 @@
/en/stable/caching.html /develop/concepts/architecture/caching
/en/stable/changelog.html /develop/quick-reference/release-notes
/en/stable/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/stable/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/stable/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/stable/getting_started.html /get-started
/en/stable/index.html /
/en/stable/installation.html /get-started/installation
/en/stable/main_concepts.html /get-started/fundamentals/main-concepts
/en/stable/publish_streamlit_components.html /develop/concepts/custom-components/publish
/en/stable/session_state_api.html /develop/api-reference/caching-and-state/st.session_state
-/en/stable/streamlit_components.html /develop/concepts/custom-components/create
+/en/stable/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/stable/streamlit_components_faq.html /knowledge-base/components
/en/stable/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/stable/streamlit_faq.html /knowledge-base
@@ -99,13 +99,13 @@
/en/0.63.0/caching.html /develop/concepts/architecture/caching
/en/0.63.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.63.0/cli.html /get-started
-/en/0.63.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.63.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.63.0/getting_started.html /get-started
/en/0.63.0/index.html /
/en/0.63.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.63.0/pre_release_features.html /get-started
/en/0.63.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.63.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.63.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.63.0/streamlit_components_faq.html /knowledge-base/components
/en/0.63.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
/en/0.63.0/troubleshooting/clean-install.html /get-started/installation
@@ -122,13 +122,13 @@
/en/0.64.0/caching.html /develop/concepts/architecture/caching
/en/0.64.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.64.0/cli.html /get-started
-/en/0.64.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.64.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.64.0/getting_started.html /get-started
/en/0.64.0/index.html /
/en/0.64.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.64.0/pre_release_features.html /get-started
/en/0.64.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.64.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.64.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.64.0/streamlit_components_faq.html /knowledge-base/components
/en/0.64.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
/en/0.64.0/troubleshooting/clean-install.html /get-started/installation
@@ -145,13 +145,13 @@
/en/0.65.0/caching.html /develop/concepts/architecture/caching
/en/0.65.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.65.0/cli.html /get-started
-/en/0.65.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.65.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.65.0/getting_started.html /get-started
/en/0.65.0/index.html /
/en/0.65.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.65.0/pre_release_features.html /get-started
/en/0.65.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.65.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.65.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.65.0/streamlit_faq.html /knowledge-base
/en/0.65.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
/en/0.65.0/troubleshooting/clean-install.html /get-started/installation
@@ -168,13 +168,13 @@
/en/0.66.0/caching.html /develop/concepts/architecture/caching
/en/0.66.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.66.0/cli.html /get-started
-/en/0.66.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.66.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.66.0/getting_started.html /get-started
/en/0.66.0/index.html /
/en/0.66.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.66.0/pre_release_features.html /get-started
/en/0.66.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.66.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.66.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.66.0/streamlit_faq.html /knowledge-base
/en/0.66.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
/en/0.66.0/troubleshooting/clean-install.html /get-started/installation
@@ -191,13 +191,13 @@
/en/0.67.0/caching.html /develop/concepts/architecture/caching
/en/0.67.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.67.0/cli.html /get-started
-/en/0.67.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.67.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.67.0/getting_started.html /get-started
/en/0.67.0/index.html /
/en/0.67.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.67.0/pre_release_features.html /get-started
/en/0.67.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.67.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.67.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.67.0/streamlit_faq.html /knowledge-base
/en/0.67.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
/en/0.67.0/troubleshooting/clean-install.html /get-started/installation
@@ -214,14 +214,14 @@
/en/0.68.0/caching.html /develop/concepts/architecture/caching
/en/0.68.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.68.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.68.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.68.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.68.0/getting_started.html /get-started
/en/0.68.0/getting_started.md /get-started
/en/0.68.0/index.html /
/en/0.68.0/installation.html /get-started/installation
/en/0.68.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.68.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.68.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.68.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.68.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.68.0/streamlit_faq.html /knowledge-base
/en/0.68.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -237,14 +237,14 @@
/en/0.69.0/caching.html /develop/concepts/architecture/caching
/en/0.69.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.69.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.69.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.69.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.69.0/getting_started.html /get-started
/en/0.69.0/getting_started.md /get-started
/en/0.69.0/index.html /
/en/0.69.0/installation.html /get-started/installation
/en/0.69.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.69.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.69.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.69.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.69.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.69.0/streamlit_faq.html /knowledge-base
/en/0.69.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -260,14 +260,14 @@
/en/0.70.0/caching.html /develop/concepts/architecture/caching
/en/0.70.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.70.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.70.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.70.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.70.0/getting_started.html /get-started
/en/0.70.0/getting_started.md /get-started
/en/0.70.0/index.html /
/en/0.70.0/installation.html /get-started/installation
/en/0.70.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.70.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.70.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.70.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.70.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.70.0/streamlit_faq.html /knowledge-base
/en/0.70.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -283,14 +283,14 @@
/en/0.71.0/caching.html /develop/concepts/architecture/caching
/en/0.71.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.71.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.71.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.71.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.71.0/getting_started.html /get-started
/en/0.71.0/getting_started.md /get-started
/en/0.71.0/index.html /
/en/0.71.0/installation.html /get-started/installation
/en/0.71.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.71.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.71.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.71.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.71.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.71.0/streamlit_faq.html /knowledge-base
/en/0.71.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -306,14 +306,14 @@
/en/0.72.0/caching.html /develop/concepts/architecture/caching
/en/0.72.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.72.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.72.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.72.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.72.0/getting_started.html /get-started
/en/0.72.0/getting_started.md /get-started
/en/0.72.0/index.html /
/en/0.72.0/installation.html /get-started/installation
/en/0.72.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.72.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.72.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.72.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.72.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.72.0/streamlit_faq.html /knowledge-base
/en/0.72.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -329,14 +329,14 @@
/en/0.73.0/caching.html /develop/concepts/architecture/caching
/en/0.73.0/changelog.html /develop/quick-reference/release-notes/2020
/en/0.73.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.73.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.73.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.73.0/getting_started.html /get-started
/en/0.73.0/getting_started.md /get-started
/en/0.73.0/index.html /
/en/0.73.0/installation.html /get-started/installation
/en/0.73.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.73.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.73.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.73.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.73.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.73.0/streamlit_faq.html /knowledge-base
/en/0.73.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -352,14 +352,14 @@
/en/0.74.0/caching.html /develop/concepts/architecture/caching
/en/0.74.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.74.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.74.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.74.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.74.0/getting_started.html /get-started
/en/0.74.0/getting_started.md /get-started
/en/0.74.0/index.html /
/en/0.74.0/installation.html /get-started/installation
/en/0.74.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.74.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.74.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.74.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.74.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.74.0/streamlit_faq.html /knowledge-base
/en/0.74.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -375,14 +375,14 @@
/en/0.75.0/caching.html /develop/concepts/architecture/caching
/en/0.75.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.75.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.75.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.75.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.75.0/getting_started.html /get-started
/en/0.75.0/getting_started.md /get-started
/en/0.75.0/index.html /
/en/0.75.0/installation.html /get-started/installation
/en/0.75.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.75.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.75.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.75.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.75.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.75.0/streamlit_faq.html /knowledge-base
/en/0.75.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -398,14 +398,14 @@
/en/0.76.0/caching.html /develop/concepts/architecture/caching
/en/0.76.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.76.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.76.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.76.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.76.0/getting_started.html /get-started
/en/0.76.0/getting_started.md /get-started
/en/0.76.0/index.html /
/en/0.76.0/installation.html /get-started/installation
/en/0.76.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.76.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.76.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.76.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.76.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.76.0/streamlit_faq.html /knowledge-base
/en/0.76.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -421,14 +421,14 @@
/en/0.77.0/caching.html /develop/concepts/architecture/caching
/en/0.77.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.77.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.77.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.77.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.77.0/getting_started.html /get-started
/en/0.77.0/getting_started.md /get-started
/en/0.77.0/index.html /
/en/0.77.0/installation.html /get-started/installation
/en/0.77.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.77.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.77.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.77.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.77.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.77.0/streamlit_faq.html /knowledge-base
/en/0.77.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -444,14 +444,14 @@
/en/0.78.0/caching.html /develop/concepts/architecture/caching
/en/0.78.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.78.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.78.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.78.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.78.0/getting_started.html /get-started
/en/0.78.0/getting_started.md /get-started
/en/0.78.0/index.html /
/en/0.78.0/installation.html /get-started/installation
/en/0.78.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.78.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.78.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.78.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.78.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.78.0/streamlit_faq.html /knowledge-base
/en/0.78.0/troubleshooting/caching_issues.html /knowledge-base/using-streamlit/caching-issues
@@ -466,13 +466,13 @@
/en/0.79.0/caching.html /develop/concepts/architecture/caching
/en/0.79.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.79.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.79.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.79.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.79.0/getting_started.html /get-started
/en/0.79.0/index.html /
/en/0.79.0/installation.html /get-started/installation
/en/0.79.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.79.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.79.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.79.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.79.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.79.0/streamlit_faq.html /knowledge-base
/en/0.79.0/theme_options.html /develop/concepts/configuration/theming
@@ -488,13 +488,13 @@
/en/0.80.0/caching.html /develop/concepts/architecture/caching
/en/0.80.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.80.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.80.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.80.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.80.0/getting_started.html /get-started
/en/0.80.0/index.html /
/en/0.80.0/installation.html /get-started/installation
/en/0.80.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.80.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.80.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.80.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.80.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.80.0/streamlit_faq.html /knowledge-base
/en/0.80.0/theme_options.html /develop/concepts/configuration/theming
@@ -510,13 +510,13 @@
/en/0.81.0/caching.html /develop/concepts/architecture/caching
/en/0.81.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.81.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.81.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.81.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.81.0/getting_started.html /get-started
/en/0.81.0/index.html /
/en/0.81.0/installation.html /get-started/installation
/en/0.81.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.81.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.81.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.81.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.81.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.81.0/streamlit_faq.html /knowledge-base
/en/0.81.0/theme_options.html /develop/concepts/configuration/theming
@@ -532,13 +532,13 @@
/en/0.81.1/caching.html /develop/concepts/architecture/caching
/en/0.81.1/changelog.html /develop/quick-reference/release-notes/2021
/en/0.81.1/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.81.1/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.81.1/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.81.1/getting_started.html /get-started
/en/0.81.1/index.html /
/en/0.81.1/installation.html /get-started/installation
/en/0.81.1/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.81.1/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.81.1/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.81.1/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.81.1/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.81.1/streamlit_faq.html /knowledge-base
/en/0.81.1/theme_options.html /develop/concepts/configuration/theming
@@ -554,13 +554,13 @@
/en/0.82.0/caching.html /develop/concepts/architecture/caching
/en/0.82.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.82.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.82.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.82.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.82.0/getting_started.html /get-started
/en/0.82.0/index.html /
/en/0.82.0/installation.html /get-started/installation
/en/0.82.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.82.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.82.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.82.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.82.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.82.0/streamlit_faq.html /knowledge-base
/en/0.82.0/theme_options.html /develop/concepts/configuration/theming
@@ -576,13 +576,13 @@
/en/0.83.0/caching.html /develop/concepts/architecture/caching
/en/0.83.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.83.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.83.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.83.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.83.0/getting_started.html /get-started
/en/0.83.0/index.html /
/en/0.83.0/installation.html /get-started/installation
/en/0.83.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.83.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
-/en/0.83.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.83.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.83.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.83.0/streamlit_faq.html /knowledge-base
/en/0.83.0/theme_options.html /develop/concepts/configuration/theming
@@ -607,14 +607,14 @@
/en/0.84.0/caching.html /develop/concepts/architecture/caching
/en/0.84.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.84.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.84.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.84.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.84.0/getting_started.html /get-started
/en/0.84.0/index.html /
/en/0.84.0/installation.html /get-started/installation
/en/0.84.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.84.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
/en/0.84.0/session_state_api.html /develop/api-reference/caching-and-state/st.session_state
-/en/0.84.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.84.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.84.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.84.0/streamlit_faq.html /knowledge-base
/en/0.84.0/theme_options.html /develop/concepts/configuration/theming
@@ -639,14 +639,14 @@
/en/0.85.0/caching.html /develop/concepts/architecture/caching
/en/0.85.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.85.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.85.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.85.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.85.0/getting_started.html /get-started
/en/0.85.0/index.html /
/en/0.85.0/installation.html /get-started/installation
/en/0.85.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.85.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
/en/0.85.0/session_state_api.html /develop/api-reference/caching-and-state/st.session_state
-/en/0.85.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.85.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.85.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.85.0/streamlit_faq.html /knowledge-base
/en/0.85.0/theme_options.html /develop/concepts/configuration/theming
@@ -672,14 +672,14 @@
/en/0.86.0/caching.html /develop/concepts/architecture/caching
/en/0.86.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.86.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.86.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.86.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.86.0/getting_started.html /get-started
/en/0.86.0/index.html /
/en/0.86.0/installation.html /get-started/installation
/en/0.86.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.86.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
/en/0.86.0/session_state_api.html /develop/api-reference/caching-and-state/st.session_state
-/en/0.86.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.86.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.86.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.86.0/streamlit_faq.html /knowledge-base
/en/0.86.0/theme_options.html /develop/concepts/configuration/theming
@@ -705,14 +705,14 @@
/en/0.87.0/caching.html /develop/concepts/architecture/caching
/en/0.87.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.87.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.87.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.87.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.87.0/getting_started.html /get-started
/en/0.87.0/index.html /
/en/0.87.0/installation.html /get-started/installation
/en/0.87.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.87.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
/en/0.87.0/session_state_api.html /develop/api-reference/caching-and-state/st.session_state
-/en/0.87.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.87.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.87.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.87.0/streamlit_faq.html /knowledge-base
/en/0.87.0/theme_options.html /develop/concepts/configuration/theming
@@ -738,14 +738,14 @@
/en/0.88.0/caching.html /develop/concepts/architecture/caching
/en/0.88.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.88.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.88.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.88.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.88.0/getting_started.html /get-started
/en/0.88.0/index.html /
/en/0.88.0/installation.html /get-started/installation
/en/0.88.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.88.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
/en/0.88.0/session_state_api.html /develop/api-reference/caching-and-state/st.session_state
-/en/0.88.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.88.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.88.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.88.0/streamlit_faq.html /knowledge-base
/en/0.88.0/theme_options.html /develop/concepts/configuration/theming
@@ -771,14 +771,14 @@
/en/0.89.0/caching.html /develop/concepts/architecture/caching
/en/0.89.0/changelog.html /develop/quick-reference/release-notes/2021
/en/0.89.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/0.89.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/0.89.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/0.89.0/getting_started.html /get-started
/en/0.89.0/index.html /
/en/0.89.0/installation.html /get-started/installation
/en/0.89.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/0.89.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
/en/0.89.0/session_state_api.html /develop/api-reference/caching-and-state/st.session_state
-/en/0.89.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/0.89.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/0.89.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/0.89.0/streamlit_faq.html /knowledge-base
/en/0.89.0/theme_options.html /develop/concepts/configuration/theming
@@ -804,14 +804,14 @@
/en/1.0.0/caching.html /develop/concepts/architecture/caching
/en/1.0.0/changelog.html /develop/quick-reference/release-notes/2021
/en/1.0.0/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
-/en/1.0.0/develop_streamlit_components.html /develop/concepts/custom-components/intro
+/en/1.0.0/develop_streamlit_components.html /develop/concepts/custom-components/v1/intro
/en/1.0.0/getting_started.html /get-started
/en/1.0.0/index.html /
/en/1.0.0/installation.html /get-started/installation
/en/1.0.0/main_concepts.html /get-started/fundamentals/main-concepts
/en/1.0.0/publish_streamlit_components.html /develop/concepts/custom-components/publish
/en/1.0.0/session_state_api.html /develop/api-reference/caching-and-state/st.session_state
-/en/1.0.0/streamlit_components.html /develop/concepts/custom-components/create
+/en/1.0.0/streamlit_components.html /develop/concepts/custom-components/v1/create
/en/1.0.0/streamlit_configuration.html /develop/api-reference/configuration/config.toml
/en/1.0.0/streamlit_faq.html /knowledge-base
/en/1.0.0/theme_options.html /develop/concepts/configuration/theming
@@ -833,7 +833,7 @@
/deploy_streamlit_app.html /deploy/streamlit-community-cloud/deploy-your-app
/tutorial/create_a_data_explorer_app.html /get-started/tutorials/create-an-app
/getting_started.html /get-started
-/develop_streamlit_components.html /develop/concepts/custom-components/create
+/develop_streamlit_components.html /develop/concepts/custom-components/v1/create
/en/component_docs/ /develop/concepts/custom-components
/api.html /develop/api-reference
/en/stable/pre_release_features.html /develop/quick-reference/prerelease
@@ -1066,8 +1066,8 @@
/library/advanced-features/app-testing/examples /develop/concepts/app-testing/examples
/library/advanced-features/app-testing/cheat-sheet /develop/concepts/app-testing/cheat-sheet
/library/components /develop/concepts/custom-components
-/library/components/components-api /develop/concepts/custom-components/intro
-/library/components/create /develop/concepts/custom-components/create
+/library/components/components-api /develop/concepts/custom-components/v1/intro
+/library/components/create /develop/concepts/custom-components/v1/create
/library/components/publish /develop/concepts/custom-components/publish
/library/changelog /develop/quick-reference/release-notes
/library/cheatsheet /develop/quick-reference/cheat-sheet
@@ -1154,6 +1154,10 @@
/develop/tutorials/llms/build-conversational-apps /develop/tutorials/chat-and-llm-apps/build-conversational-apps
/develop/tutorials/llms/llm-quickstart /develop/tutorials/chat-and-llm-apps/llm-quickstart
/knowledge-base/deploy/authentication-without-sso /develop/concepts/connections/authentication
+/develop/concepts/custom-components/intro /develop/concepts/custom-components/v1/intro
+/develop/concepts/custom-components/create /develop/concepts/custom-components/v1/create
+/develop/concepts/custom-components/limitations /develop/concepts/custom-components/v1/limitations
+
# Deep links included in streamlit/streamlit source code
/st.connections.snowflakeconnection-configuration /develop/api-reference/connections/st.connections.snowflakeconnection