R

ReflexKR

Reflex Docs

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

The Component Workshop: Reflex's 100 Library Components
Data display

Icon

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).

Try the props

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))
stroke_width is the line thickness. color is given as rx.color(color, shade). size only takes integers, so it gets its own example below.
PropValuesDefaultUse
tag (or first argument)Icon nameRequiredWhich icon
sizeInteger (pixels)24Width and height
stroke_widthNumber2Line thickness
colorColor name, rx.color(...)Text colorLine color; without it, follows the surrounding text color

Stroke width and size

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

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",
)

Dynamic icons: choosing with rx.match

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",
)

Dynamic icon names

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",
)

Filling the order

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.

← Previous

Data display · Avatar

Next →

Data display · Callout

Get news about new lessons

We'll email you when this course gets new lessons or a follow-up course opens.

We collect: your email address · Purpose: news about new lessons or the launch of this course · Kept until: you ask us to remove it. We never use it for anything else or share it. Reply to any notice email and we'll delete it right away.

Questions & answers

Ask anything about this lesson. Questions from every language version of this page appear together.

Shown as plain text, without links or formatting.

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
한국어English日本語简体中文EspañolDeutsch

© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0

Built with Reflex