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.iconOfficial docs
Workshop order
Put a magnifying glass in front of the search box, and shipping and return icons in front of the product notes.
rx.icon shows one picture from the Lucide icon set. Pass the icon name as the first argument or as tag. Names are snake_case by default, but kebab-case copied straight from the Lucide site works too.
rx.flex(
rx.icon("calendar"),
rx.icon(tag="calendar"),
rx.icon("circle_check_big"),
rx.icon("circle-check-big"),
spacing="2",
)At the top of the official docs is a list where you can search every icon and copy its name. Pick your icons from that list or from the Lucide site. If you use a name that isn't in the list, you get a warning at compile time and the icon turns into a question mark (circle_help).
Three props shape a Lucide icon: size, stroke_width and color. This lab passes the icon name as a State value too, so it renders the way described under "Dynamic icon names" below.
Try the props
tag
stroke_width
2
color
rx.icon("heart", size=48, stroke_width=2, color=rx.color("indigo", 9))| Prop | Values | Default | Use |
|---|---|---|---|
tag (or first argument) | Icon name | Required | Which icon |
size | Integer (pixels) | 24 | Width and height |
stroke_width | Number | 2 | Line thickness |
color | Color name, rx.color(...) | Text color | Line color; without it, follows the surrounding text color |
stroke_width is the thickness of the lines. Smaller numbers look lighter and finer.
rx.flex(
rx.icon("moon", stroke_width=1),
rx.icon("moon", stroke_width=1.5),
rx.icon("moon", stroke_width=2),
rx.icon("moon", stroke_width=2.5),
spacing="2",
)size is an integer in pixels. When the icon sits next to text, match it roughly to the font size.
rx.flex(
rx.icon("zoom_in", size=15),
rx.icon("zoom_in", size=20),
rx.icon("zoom_in", size=25),
rx.icon("zoom_in", size=30),
align="center",
spacing="2",
)color accepts basic color names.
rx.flex(
rx.icon("zoom_in", size=18, color="indigo"),
rx.icon("zoom_in", size=18, color="cyan"),
rx.icon("zoom_in", size=18, color="orange"),
rx.icon("zoom_in", size=18, color="crimson"),
spacing="2",
)You can also pass a Radix color with a shade from 1 to 12, as in rx.color("purple", 6). "accent" is the theme's main color, so when the theme changes, the icon color follows. The top row shows purple and the bottom row accent, in shades 1 to 12.
rx.flex(
rx.flex(*[rx.icon("zoom_in", size=18, color=rx.color("purple", i)) for i in range(1, 13)], spacing="2"),
rx.flex(*[rx.icon("zoom_in", size=18, color=rx.color("accent", i)) for i in range(1, 13)], spacing="2"),
direction="column",
spacing="2",
)When the icons you need come from a fixed handful, use rx.match to pick the one that fits the State value. Every icon is compiled ahead of time, so this is the safest approach.
class IconMatchState(rx.State):
op: str = "plus"
@rx.event
def set_icon_op(self, value: str | list[str]):
if isinstance(value, str):
self.op = value
rx.flex(
rx.segmented_control.root(
rx.segmented_control.item("plus", value="plus"),
rx.segmented_control.item("minus", value="minus"),
rx.segmented_control.item("equal", value="equal"),
value=IconMatchState.op,
on_change=IconMatchState.set_icon_op,
),
rx.match(
IconMatchState.op,
("plus", rx.icon("plus")),
("minus", rx.icon("minus")),
("equal", rx.icon("equal")),
),
spacing="3",
align="center",
)You can also pass a State value straight to tag. Reflex then uses a DynamicIcon component instead, which loads the icon at runtime. That lets you use any Lucide icon, but a name that doesn't exist causes a runtime error, so make sure the names are correct.
The catch: with this approach Reflex bundles every Lucide icon (about 1,700) as a separate file at build time, so the build grows a lot. That is why this page shows only the code, without a live demo. If you know which icons you need, use the rx.match approach above.
import random
class IconDynamicState(rx.State):
current_icon: str = "heart"
@rx.event
def change_icon(self):
icons = ["heart", "star", "bell", "calendar", "settings"]
self.current_icon = random.choice([i for i in icons if i != self.current_icon])
rx.vstack(
rx.icon(IconDynamicState.current_icon, size=30, color="red"),
rx.text(IconDynamicState.current_icon, size="2", color_scheme="gray"),
rx.button("Change Icon", on_click=IconDynamicState.change_icon),
spacing="3",
align="center",
)Icons go in as children of other components. Put a magnifying glass inside a badge to make a search-box look, and place colored icons in front of the notes.
Search documentation...
Free shipping
30-day returns
rx.flex(
rx.badge(
rx.flex(
rx.icon("search", size=18),
rx.text("Search documentation...", size="3", weight="medium"),
spacing="1",
align="center",
),
size="2",
radius="full",
color_scheme="gray",
),
rx.flex(
rx.icon("truck", color=rx.color("green", 9)),
rx.text("Free shipping"),
rx.icon("rotate-ccw", color=rx.color("amber", 9)),
rx.text("30-day returns"),
spacing="2",
align="center",
),
direction="column",
spacing="3",
)Workshop notes
rx.icon("name") or rx.icon(tag="name"). Both snake_case and kebab-case work.
Shape it with size (integer pixels), stroke_width (line thickness) and color (a color name or rx.color).
To choose among a few, use rx.match; passing any name through State uses DynamicIcon.
A wrong dynamic name is a runtime error. A wrong fixed name gives a compile warning and turns into circle_help.
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.