The Component Workshop: Reflex's 100 Library Components
·
Course overview
Layout
·
Box
·
Flex
·
Stack
·
Grid
·
Container
·
Section
·
Center
·
Spacer
·
Separator
·
Card
·
Inset
·
Aspect Ratio
·
Fragment
Typography
·
Text
·
Heading
·
Link
·
Code
·
Markdown
·
Blockquote
·
Quote
·
Strong
·
Em
·
Kbd
Forms
·
Button
·
Input
·
Text Area
·
Checkbox
·
Switch
·
Radio Group
·
Select
·
Slider
·
Form
·
Upload
Data display
·
Badge
·
Avatar
·
Icon
·
Callout
·
List
·
Data List
·
Code Block
·
Progress
·
Spinner
·
Scroll Area
·
Moment
Disclosure
·
Tabs
·
Accordion
·
Segmented Control
Overlay
·
Tooltip
·
Popover
·
Hover Card
·
Dialog
·
Alert Dialog
·
Drawer
·
Dropdown Menu
·
Context Menu
·
Toast
Dynamic rendering
·
Cond
·
Match
·
Foreach
·
Auto Scroll
Media
·
Image
·
Audio
·
Video
Tables and data grids
·
Table
·
Data Table
·
Data Editor
Charts
·
Area Chart
·
Bar Chart
·
Line Chart
·
Composed Chart
·
Pie Chart
·
Radar Chart
·
Radial Bar Chart
·
Scatter Chart
·
Funnel Chart
·
Treemap
·
Sankey Chart
·
Error Bar
Chart parts
·
Axis
·
Cartesian Grid
·
Chart Tooltip
·
Legend
·
Label
·
Reference
·
Brush
Other chart libraries
·
Plotly
·
Pyplot
HTML elements
·
HTML
·
HTML Text
·
HTML Layout
·
HTML Forms
·
HTML Media
·
HTML Tables
·
SVG
Other tools
·
Theme
·
Skeleton
·
Clipboard
·
Html Embed
·
Script
·
Memo
rx.clipboardOfficial docs
Workshop order
In the bug report form, make an area where a screenshot is attached as soon as the user pastes it.
rx.clipboard listens for paste events and hands the pasted content to the State, sorted by type. It accepts not only text but also binary data such as images.
It's an invisible component that draws nothing on screen and listens for pastes that happen in the children it wraps. It has been available since Reflex 0.5.6.
class ClipboardBasicState(rx.State):
items: list[str] = []
@rx.event
def on_paste(self, data: list[tuple[str, str]]):
self.items = [f"{mime_type}: {item[:60]}" for mime_type, item in data]
rx.vstack(
rx.clipboard(
rx.input(placeholder="Copy some text, then paste here"),
on_paste=ClipboardBasicState.on_paste,
),
rx.foreach(ClipboardBasicState.items, lambda line: rx.code(line, size="1")),
width="100%",
max_width="420px",
)rx.clipboard has no visible props, so instead of a prop lab, here is an example that reacts to pasting.
Paste text and you get text/plain; paste text copied from a web page and text/html comes along too; paste an image and you get a type such as image/png.
Paste events: 0
class ClipboardTypesState(rx.State):
count: int = 0
types: list[str] = []
@rx.event
def on_paste(self, data: list[tuple[str, str]]):
self.count += 1
self.types = [mime_type for mime_type, _ in data]
rx.card(
rx.clipboard(
rx.text_area(placeholder="Paste text, an image, or a copied web page", rows="3"),
on_paste=ClipboardTypesState.on_paste,
),
rx.text("Paste events: ", ClipboardTypesState.count, size="2", margin_top="8px"),
rx.flex(rx.foreach(ClipboardTypesState.types, lambda t: rx.badge(t)), spacing="2", wrap="wrap", margin_top="6px"),
max_width="420px",
)| Prop | Values | Default | Use |
|---|---|---|---|
on_paste | event handler | none | Receives a list of (MIME type, data) tuples |
targets | list of element ids | the children, or the whole document if there are none | Elements to listen to for pastes |
.stop_propagation | event action | none | Keeps the event from reaching outer paste handlers |
.prevent_default | event action | none | Blocks the default action of actually pasting into the input |
The data that on_paste receives is a list of (mime_type, data) tuples. Text arrives as a plain string,
and binary data such as images arrives as a base64-encoded data URI (data:image/png;base64,...). That string can go straight into the src of rx.image,
and if you need the bytes on the server, you can decode it in Python with urllib.request.urlopen(data_uri).read().
Place just rx.clipboard() with no children and it attaches to the document's paste event, so it fires wherever on the page you paste.
Doing that on this page would catch the pastes of every other example too, so the official docs' example is shown as code only.
class ClipboardPasteState(rx.State):
@rx.event
def on_paste(self, data: list[tuple[str, str]]):
for mime_type, item in data:
yield rx.toast(f"Pasted {mime_type} data: {item}")
def clipboard_example():
return rx.fragment(
rx.clipboard(on_paste=ClipboardPasteState.on_paste), # no children: listens for paste on the whole document
"Paste Content Here",
)To receive pastes only in a particular element, wrap that element in rx.clipboard. If there's a page-wide handler outside, use .stop_propagation to keep the event from bubbling up.
Add .prevent_default and the text isn't actually pasted into the input. Paste some text into the second input and the field stays empty.
No image yet. Copy an image (or take a screenshot) and paste above.
class ClipboardImageState(rx.State):
last_image_uri: str = ""
@rx.event
def on_paste(self, data: list[tuple[str, str]]):
for mime_type, item in data:
if mime_type.startswith("image/"):
if len(item) > 2_000_000:
return rx.toast("This image is too large for the demo")
self.last_image_uri = item
break
else:
return rx.toast("Did not find an image in the pasted data")
rx.vstack(
rx.clipboard(
rx.input(placeholder="Paste Image (stop propagation)"),
on_paste=ClipboardImageState.on_paste.stop_propagation,
),
rx.clipboard(
rx.input(placeholder="Paste Image (prevent default)"),
on_paste=ClipboardImageState.on_paste.prevent_default,
),
rx.cond(
ClipboardImageState.last_image_uri != "",
rx.image(src=ClipboardImageState.last_image_uri, alt="Image pasted from clipboard", max_width="240px", border_radius="6px"),
rx.text("No image yet. Copy an image (or take a screenshot) and paste above.", size="2", color_scheme="gray"),
),
width="100%",
max_width="420px",
)Give targets the ids of elements and it listens to just those elements without wrapping them. When you wrap children, Reflex adds an id to them and fills in targets automatically.
Pasted characters: 0
class ClipboardTargetState(rx.State):
pasted_chars: int = 0
@rx.event
def on_paste(self, data: list[tuple[str, str]]):
self.pasted_chars += sum(len(item) for mime_type, item in data if mime_type == "text/plain")
rx.vstack(
rx.clipboard(on_paste=ClipboardTargetState.on_paste, targets=["clipboard_target_note"]),
rx.text_area(id="clipboard_target_note", placeholder="Only this box is watched", rows="2"),
rx.input(placeholder="This box is not watched"),
rx.text("Pasted characters: ", ClipboardTargetState.pasted_chars, size="2"),
width="100%",
max_width="420px",
)Click the dashed box to focus it, paste a screenshot, and the image is attached. The box isn't an input, so tab_index=0 lets it receive focus,
and event actions are chained, as in .prevent_default.stop_propagation. The image goes into the State as a data URI, so images that are too large are filtered out.
Click here, then paste a screenshot (Ctrl + V)
class ClipboardTicketState(rx.State):
shot: str = ""
note: str = ""
@rx.event
def on_paste(self, data: list[tuple[str, str]]):
for mime_type, item in data:
if mime_type.startswith("image/") and len(item) <= 2_000_000:
self.shot = item
return
return rx.toast("Paste a screenshot (an image) here")
@rx.event
def change_note(self, value: str):
self.note = value
@rx.event
def clear_shot(self):
self.shot = ""
rx.card(
rx.heading("Bug report", size="3"),
rx.text_area(
value=ClipboardTicketState.note,
on_change=ClipboardTicketState.change_note,
placeholder="What went wrong?",
rows="2",
margin_y="8px",
),
rx.clipboard(
rx.box(
rx.cond(
ClipboardTicketState.shot != "",
rx.image(src=ClipboardTicketState.shot, alt="Pasted screenshot", max_height="160px"),
rx.text("Click here, then paste a screenshot (Ctrl + V)", size="2", color_scheme="gray"),
),
tab_index=0,
padding="16px",
border=f"2px dashed {rx.color('gray', 7)}",
border_radius="8px",
text_align="center",
),
on_paste=ClipboardTicketState.on_paste.prevent_default.stop_propagation,
),
rx.button("Remove screenshot", on_click=ClipboardTicketState.clear_shot, variant="soft", color_scheme="gray", size="1", margin_top="8px"),
max_width="420px",
)Workshop notes
rx.clipboard(child, on_paste=...) listens for pastes in its children. Without children, the whole document.
on_paste receives [(mime_type, data), ...]. Binary data is a base64 data URI.
A data URI can be used directly as the src of rx.image.
.stop_propagation keeps it from outer handlers; .prevent_default blocks the actual paste.
targets=[id, ...] listens to specific elements without wrapping them.
Get news about new lessons
We'll email you when this course gets new lessons or a follow-up course opens.
R
ReflexKR
Learn Python and Reflex by doing. Every example was run and verified on Reflex 0.10.0.
ReflexKR is free, with no banner ads. If it helped you, you can support it with a coffee. ☕ Buy us a coffee
Affiliate disclosure© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Questions & answers
Ask anything about this lesson. Questions from every language version of this page appear together.