pypi-streamlit

Description
The fastest way to build and share data apps
Author
tessl
Last updated

How to use

npx @tessl/cli registry install tessl/pypi-streamlit@1.16.0

custom-components.md docs/

1
# Custom Components
2
3
Framework 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.
4
5
## Capabilities
6
7
### Component Declaration
8
9
Create custom components that can be reused across applications.
10
11
```python { .api }
12
def declare_component(
13
name: str,
14
path: str = None,
15
url: str = None
16
) -> ComponentCallable:
17
"""
18
Declare a custom Streamlit component.
19
20
Parameters:
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)
24
25
Returns:
26
ComponentCallable: Function that can be called to render the component
27
"""
28
```
29
30
#### Usage Example
31
32
```python
33
import streamlit as st
34
import streamlit.components.v1 as components
35
36
# Declare a custom component during development
37
_my_component = components.declare_component(
38
"my_component",
39
path="./my_component/build" # Path to built component
40
)
41
42
# Declare component for production
43
_my_component = components.declare_component(
44
"my_component",
45
url="https://my-component-cdn.com/my_component"
46
)
47
48
# Use the component
49
def my_component(message, key=None):
50
"""Wrapper function for the custom component."""
51
return _my_component(
52
message=message,
53
key=key,
54
default=None
55
)
56
57
# Call the component
58
result = my_component("Hello from custom component!", key="my_comp")
59
if result:
60
st.write(f"Component returned: {result}")
61
```
62
63
### HTML Rendering
64
65
Render raw HTML content within Streamlit apps.
66
67
```python { .api }
68
def html(body: str, width: int = None, height: int = None, scrolling: bool = False) -> None:
69
"""
70
Render HTML content in an iframe.
71
72
Parameters:
73
- body: HTML string to render
74
- 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 iframe
77
"""
78
```
79
80
#### Usage Example
81
82
```python
83
import streamlit as st
84
import streamlit.components.v1 as components
85
86
# Simple HTML rendering
87
components.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)
92
93
# Interactive HTML with JavaScript
94
components.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>
101
102
<script>
103
let count = 0;
104
const countDisplay = document.getElementById('count');
105
const incrementBtn = document.getElementById('increment');
106
const decrementBtn = document.getElementById('decrement');
107
108
incrementBtn.addEventListener('click', () => {
109
count++;
110
countDisplay.textContent = count;
111
});
112
113
decrementBtn.addEventListener('click', () => {
114
count--;
115
countDisplay.textContent = count;
116
});
117
</script>
118
""", height=200)
119
120
# HTML with external libraries
121
components.html("""
122
<div id="chart"></div>
123
<script src="https://d3js.org/d3.v7.min.js"></script>
124
<script>
125
const data = [4, 8, 15, 16, 23, 42];
126
const svg = d3.select("#chart")
127
.append("svg")
128
.attr("width", 400)
129
.attr("height", 200);
130
131
svg.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
```
143
144
### IFrame Embedding
145
146
Embed external web content through iframes.
147
148
```python { .api }
149
def iframe(src: str, width: int = None, height: int = None, scrolling: bool = False) -> None:
150
"""
151
Embed an external URL in an iframe.
152
153
Parameters:
154
- src: URL to embed
155
- 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 iframe
158
"""
159
```
160
161
#### Usage Example
162
163
```python
164
import streamlit as st
165
import streamlit.components.v1 as components
166
167
# Embed external website
168
st.subheader("Embedded Web Content")
169
components.iframe("https://example.com", height=400)
170
171
# Embed interactive dashboard
172
components.iframe(
173
"https://public.tableau.com/views/Dashboard/Sheet1",
174
width=800,
175
height=600,
176
scrolling=True
177
)
178
179
# Embed map
180
components.iframe(
181
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d...",
182
height=300
183
)
184
185
# Embed video
186
components.iframe(
187
"https://www.youtube.com/embed/VIDEO_ID",
188
height=315
189
)
190
```
191
192
### Advanced Component Development
193
194
Structure for building sophisticated custom components.
195
196
#### Component Development Example
197
198
```python
199
# my_component.py
200
import streamlit as st
201
import streamlit.components.v1 as components
202
import os
203
204
# Component declaration
205
_component_func = components.declare_component(
206
"my_advanced_component",
207
path=os.path.join(os.path.dirname(__file__), "frontend", "build"),
208
)
209
210
def my_advanced_component(
211
data,
212
config=None,
213
theme="light",
214
key=None
215
):
216
"""
217
Create an advanced custom component.
218
219
Parameters:
220
- data: Data to pass to the component
221
- config: Configuration dictionary
222
- theme: UI theme ("light" or "dark")
223
- key: Unique key for the component
224
225
Returns:
226
Component return value (user interactions, selections, etc.)
227
"""
228
if config is None:
229
config = {}
230
231
# Pass data to component
232
component_value = _component_func(
233
data=data,
234
config=config,
235
theme=theme,
236
key=key,
237
default=None
238
)
239
240
return component_value
241
242
# Usage in Streamlit app
243
if __name__ == "__main__":
244
st.title("Advanced Component Demo")
245
246
# Sample data
247
chart_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
}
255
256
# Component configuration
257
config = {
258
"responsive": True,
259
"maintainAspectRatio": False,
260
"plugins": {
261
"legend": {"display": True},
262
"title": {"display": True, "text": "Sales Chart"}
263
}
264
}
265
266
# Render component
267
result = my_advanced_component(
268
data=chart_data,
269
config=config,
270
theme="light",
271
key="sales_chart"
272
)
273
274
if result:
275
st.write("User interaction:", result)
276
```
277
278
#### Frontend Component Structure
279
280
```javascript
281
// frontend/src/MyComponent.tsx (React example)
282
import React, { useEffect, useState } from "react"
283
import { Streamlit, withStreamlitConnection } from "streamlit-component-lib"
284
285
interface ComponentProps {
286
args: {
287
data: any
288
config: any
289
theme: string
290
}
291
}
292
293
const MyComponent: React.FC<ComponentProps> = ({ args }) => {
294
const { data, config, theme } = args
295
const [selectedValue, setSelectedValue] = useState<string>("")
296
297
useEffect(() => {
298
// Auto-resize component height
299
Streamlit.setFrameHeight()
300
})
301
302
const handleClick = (value: string) => {
303
setSelectedValue(value)
304
// Send data back to Streamlit
305
Streamlit.setComponentValue(value)
306
}
307
308
return (
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
<button
314
key={index}
315
onClick={() => handleClick(label)}
316
className={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
}
328
329
export default withStreamlitConnection(MyComponent)
330
```
331
332
### Component Communication
333
334
Bidirectional communication between Streamlit and custom components.
335
336
#### Usage Example
337
338
```python
339
import streamlit as st
340
import streamlit.components.v1 as components
341
342
# Component that sends data back to Streamlit
343
components.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>
349
350
<script>
351
function sendData() {
352
const input = document.getElementById('user-input');
353
const data = {
354
text: input.value,
355
timestamp: new Date().toISOString()
356
};
357
358
// Send data back to Streamlit
359
window.parent.postMessage({
360
type: 'streamlit:setComponentValue',
361
value: data
362
}, '*');
363
}
364
</script>
365
""", height=150, key="data_entry")
366
367
# Receive data from component
368
result = st.session_state.get("data_entry")
369
if result:
370
st.write(f"Received from component: {result}")
371
```
372
373
### Component Integration Patterns
374
375
Common patterns for integrating custom components.
376
377
#### Usage Example
378
379
```python
380
import streamlit as st
381
import streamlit.components.v1 as components
382
import json
383
384
# Pattern 1: Data Visualization Component
385
def render_custom_chart(data, chart_type="bar"):
386
"""Render a custom chart component."""
387
chart_html = f"""
388
<div id="custom-chart"></div>
389
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
390
<script>
391
const ctx = document.getElementById('custom-chart').getContext('2d');
392
new Chart(ctx, {{
393
type: '{chart_type}',
394
data: {json.dumps(data)},
395
options: {{
396
responsive: true,
397
plugins: {{
398
title: {{
399
display: true,
400
text: 'Custom Chart'
401
}}
402
}}
403
}}
404
}});
405
</script>
406
"""
407
408
components.html(chart_html, height=400)
409
410
# Pattern 2: Form Component
411
def custom_form_component():
412
"""Create a custom form with validation."""
413
form_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>
429
430
<script>
431
document.getElementById('custom-form').addEventListener('submit', function(e) {
432
e.preventDefault();
433
const formData = {
434
name: document.getElementById('name').value,
435
email: document.getElementById('email').value,
436
message: document.getElementById('message').value
437
};
438
439
window.parent.postMessage({
440
type: 'streamlit:setComponentValue',
441
value: formData
442
}, '*');
443
});
444
</script>
445
"""
446
447
return components.html(form_html, height=300, key="custom_form")
448
449
# Use the patterns
450
st.title("Custom Component Patterns")
451
452
# Chart pattern
453
chart_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
}
461
462
render_custom_chart(chart_data, "doughnut")
463
464
# Form pattern
465
form_result = custom_form_component()
466
if form_result:
467
st.success("Form submitted!")
468
st.json(form_result)
469
```
470
471
## Component Development Guidelines
472
473
- **Component Structure**: Use modern frontend frameworks (React, Vue, Angular)
474
- **Communication**: Use `Streamlit.setComponentValue()` to send data back
475
- **Responsive Design**: Components should work on different screen sizes
476
- **State Management**: Handle component state independently from Streamlit
477
- **Performance**: Minimize component re-renders and data transfers
478
- **Security**: Sanitize user inputs and validate data
479
- **Documentation**: Provide clear usage examples and API documentation
480
481
## Component Deployment
482
483
- **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 assets
486
- **Versioning**: Version components to ensure compatibility