- Spec files
pypi-streamlit
Describes: pkg:pypi/streamlit@1.16.x
- Description
- The fastest way to build and share data apps
- Author
- tessl
- Last updated
custom-components.md docs/
1# Custom Components23Framework for creating and using custom HTML/JavaScript components. This enables extension of Streamlit's built-in widget set with reusable interactive elements that can integrate frontend technologies like React, Vue, or vanilla JavaScript.45## Capabilities67### Component Declaration89Create custom components that can be reused across applications.1011```python { .api }12def declare_component(13name: str,14path: str = None,15url: str = None16) -> ComponentCallable:17"""18Declare a custom Streamlit component.1920Parameters:21- name: Component name (must be unique)22- path: Path to component's build directory (for local development)23- url: URL of component (for production deployment)2425Returns:26ComponentCallable: Function that can be called to render the component27"""28```2930#### Usage Example3132```python33import streamlit as st34import streamlit.components.v1 as components3536# Declare a custom component during development37_my_component = components.declare_component(38"my_component",39path="./my_component/build" # Path to built component40)4142# Declare component for production43_my_component = components.declare_component(44"my_component",45url="https://my-component-cdn.com/my_component"46)4748# Use the component49def my_component(message, key=None):50"""Wrapper function for the custom component."""51return _my_component(52message=message,53key=key,54default=None55)5657# Call the component58result = my_component("Hello from custom component!", key="my_comp")59if result:60st.write(f"Component returned: {result}")61```6263### HTML Rendering6465Render raw HTML content within Streamlit apps.6667```python { .api }68def html(body: str, width: int = None, height: int = None, scrolling: bool = False) -> None:69"""70Render HTML content in an iframe.7172Parameters:73- body: HTML string to render74- width: Width of the iframe in pixels (None for auto)75- height: Height of the iframe in pixels (None for auto)76- scrolling: Whether to allow scrolling in the iframe77"""78```7980#### Usage Example8182```python83import streamlit as st84import streamlit.components.v1 as components8586# Simple HTML rendering87components.html("""88<h2 style="color: blue;">Custom HTML Content</h2>89<p>This is rendered as HTML with custom styling.</p>90<button onclick="alert('Button clicked!')">Click Me</button>91""", height=150)9293# Interactive HTML with JavaScript94components.html("""95<div id="my-component" style="padding: 20px; border: 1px solid #ccc;">96<h3>Interactive Counter</h3>97<button id="increment">+</button>98<span id="count">0</span>99<button id="decrement">-</button>100</div>101102<script>103let count = 0;104const countDisplay = document.getElementById('count');105const incrementBtn = document.getElementById('increment');106const decrementBtn = document.getElementById('decrement');107108incrementBtn.addEventListener('click', () => {109count++;110countDisplay.textContent = count;111});112113decrementBtn.addEventListener('click', () => {114count--;115countDisplay.textContent = count;116});117</script>118""", height=200)119120# HTML with external libraries121components.html("""122<div id="chart"></div>123<script src="https://d3js.org/d3.v7.min.js"></script>124<script>125const data = [4, 8, 15, 16, 23, 42];126const svg = d3.select("#chart")127.append("svg")128.attr("width", 400)129.attr("height", 200);130131svg.selectAll("rect")132.data(data)133.enter()134.append("rect")135.attr("x", (d, i) => i * 60)136.attr("y", d => 200 - d * 4)137.attr("width", 50)138.attr("height", d => d * 4)139.attr("fill", "steelblue");140</script>141""", height=220)142```143144### IFrame Embedding145146Embed external web content through iframes.147148```python { .api }149def iframe(src: str, width: int = None, height: int = None, scrolling: bool = False) -> None:150"""151Embed an external URL in an iframe.152153Parameters:154- src: URL to embed155- width: Width of the iframe in pixels (None for auto)156- height: Height of the iframe in pixels (None for auto)157- scrolling: Whether to allow scrolling in the iframe158"""159```160161#### Usage Example162163```python164import streamlit as st165import streamlit.components.v1 as components166167# Embed external website168st.subheader("Embedded Web Content")169components.iframe("https://example.com", height=400)170171# Embed interactive dashboard172components.iframe(173"https://public.tableau.com/views/Dashboard/Sheet1",174width=800,175height=600,176scrolling=True177)178179# Embed map180components.iframe(181"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d...",182height=300183)184185# Embed video186components.iframe(187"https://www.youtube.com/embed/VIDEO_ID",188height=315189)190```191192### Advanced Component Development193194Structure for building sophisticated custom components.195196#### Component Development Example197198```python199# my_component.py200import streamlit as st201import streamlit.components.v1 as components202import os203204# Component declaration205_component_func = components.declare_component(206"my_advanced_component",207path=os.path.join(os.path.dirname(__file__), "frontend", "build"),208)209210def my_advanced_component(211data,212config=None,213theme="light",214key=None215):216"""217Create an advanced custom component.218219Parameters:220- data: Data to pass to the component221- config: Configuration dictionary222- theme: UI theme ("light" or "dark")223- key: Unique key for the component224225Returns:226Component return value (user interactions, selections, etc.)227"""228if config is None:229config = {}230231# Pass data to component232component_value = _component_func(233data=data,234config=config,235theme=theme,236key=key,237default=None238)239240return component_value241242# Usage in Streamlit app243if __name__ == "__main__":244st.title("Advanced Component Demo")245246# Sample data247chart_data = {248"labels": ["Jan", "Feb", "Mar", "Apr", "May"],249"datasets": [{250"label": "Sales",251"data": [12, 19, 3, 5, 2],252"backgroundColor": "rgba(75,192,192,0.6)"253}]254}255256# Component configuration257config = {258"responsive": True,259"maintainAspectRatio": False,260"plugins": {261"legend": {"display": True},262"title": {"display": True, "text": "Sales Chart"}263}264}265266# Render component267result = my_advanced_component(268data=chart_data,269config=config,270theme="light",271key="sales_chart"272)273274if result:275st.write("User interaction:", result)276```277278#### Frontend Component Structure279280```javascript281// frontend/src/MyComponent.tsx (React example)282import React, { useEffect, useState } from "react"283import { Streamlit, withStreamlitConnection } from "streamlit-component-lib"284285interface ComponentProps {286args: {287data: any288config: any289theme: string290}291}292293const MyComponent: React.FC<ComponentProps> = ({ args }) => {294const { data, config, theme } = args295const [selectedValue, setSelectedValue] = useState<string>("")296297useEffect(() => {298// Auto-resize component height299Streamlit.setFrameHeight()300})301302const handleClick = (value: string) => {303setSelectedValue(value)304// Send data back to Streamlit305Streamlit.setComponentValue(value)306}307308return (309<div className={`component ${theme}`}>310<h3>Custom Interactive Component</h3>311<div className="data-display">312{data.labels.map((label: string, index: number) => (313<button314key={index}315onClick={() => handleClick(label)}316className={selectedValue === label ? "selected" : ""}317>318{label}: {data.datasets[0].data[index]}319</button>320))}321</div>322{selectedValue && (323<p>Selected: {selectedValue}</p>324)}325</div>326)327}328329export default withStreamlitConnection(MyComponent)330```331332### Component Communication333334Bidirectional communication between Streamlit and custom components.335336#### Usage Example337338```python339import streamlit as st340import streamlit.components.v1 as components341342# Component that sends data back to Streamlit343components.html("""344<div>345<h3>Data Entry Component</h3>346<input type="text" id="user-input" placeholder="Enter text...">347<button onclick="sendData()">Send to Streamlit</button>348</div>349350<script>351function sendData() {352const input = document.getElementById('user-input');353const data = {354text: input.value,355timestamp: new Date().toISOString()356};357358// Send data back to Streamlit359window.parent.postMessage({360type: 'streamlit:setComponentValue',361value: data362}, '*');363}364</script>365""", height=150, key="data_entry")366367# Receive data from component368result = st.session_state.get("data_entry")369if result:370st.write(f"Received from component: {result}")371```372373### Component Integration Patterns374375Common patterns for integrating custom components.376377#### Usage Example378379```python380import streamlit as st381import streamlit.components.v1 as components382import json383384# Pattern 1: Data Visualization Component385def render_custom_chart(data, chart_type="bar"):386"""Render a custom chart component."""387chart_html = f"""388<div id="custom-chart"></div>389<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>390<script>391const ctx = document.getElementById('custom-chart').getContext('2d');392new Chart(ctx, {{393type: '{chart_type}',394data: {json.dumps(data)},395options: {{396responsive: true,397plugins: {{398title: {{399display: true,400text: 'Custom Chart'401}}402}}403}}404}});405</script>406"""407408components.html(chart_html, height=400)409410# Pattern 2: Form Component411def custom_form_component():412"""Create a custom form with validation."""413form_html = """414<form id="custom-form" style="padding: 20px;">415<div style="margin-bottom: 15px;">416<label>Name:</label>417<input type="text" id="name" required>418</div>419<div style="margin-bottom: 15px;">420<label>Email:</label>421<input type="email" id="email" required>422</div>423<div style="margin-bottom: 15px;">424<label>Message:</label>425<textarea id="message" rows="4" required></textarea>426</div>427<button type="submit">Submit</button>428</form>429430<script>431document.getElementById('custom-form').addEventListener('submit', function(e) {432e.preventDefault();433const formData = {434name: document.getElementById('name').value,435email: document.getElementById('email').value,436message: document.getElementById('message').value437};438439window.parent.postMessage({440type: 'streamlit:setComponentValue',441value: formData442}, '*');443});444</script>445"""446447return components.html(form_html, height=300, key="custom_form")448449# Use the patterns450st.title("Custom Component Patterns")451452# Chart pattern453chart_data = {454"labels": ["A", "B", "C", "D"],455"datasets": [{456"label": "Dataset 1",457"data": [12, 19, 3, 5],458"backgroundColor": ["#FF6384", "#36A2EB", "#FFCE56", "#4BC0C0"]459}]460}461462render_custom_chart(chart_data, "doughnut")463464# Form pattern465form_result = custom_form_component()466if form_result:467st.success("Form submitted!")468st.json(form_result)469```470471## Component Development Guidelines472473- **Component Structure**: Use modern frontend frameworks (React, Vue, Angular)474- **Communication**: Use `Streamlit.setComponentValue()` to send data back475- **Responsive Design**: Components should work on different screen sizes476- **State Management**: Handle component state independently from Streamlit477- **Performance**: Minimize component re-renders and data transfers478- **Security**: Sanitize user inputs and validate data479- **Documentation**: Provide clear usage examples and API documentation480481## Component Deployment482483- **Development**: Use local file paths with `declare_component(path=...)`484- **Production**: Host built components and use `declare_component(url=...)`485- **Distribution**: Publish components as Python packages with built frontend assets486- **Versioning**: Version components to ensure compatibility