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
Dynamic rendering

Foreach

rx.foreach

Official docs

Workshop order

Build a to-do list. You should be able to add new tasks and remove finished ones from the list by clicking "Done".

rx.foreach(items, function) loops over a State list, tuple or dict and lays out the component the function builds for each item. When the list changes, the screen is redrawn right away. A Python for runs only once, when the page is built, so it can't be used on State lists.

Use rx.foreach for State variables, and Python list or dict comprehensions for constants that never change.

#E5484D

#12A594

#3E63DD

#AD5700

#F76B15

#8E4EC6

class ForeachColorState(rx.State):
    colors: list[str] = ["#E5484D", "#12A594", "#3E63DD", "#AD5700", "#F76B15", "#8E4EC6"]


def foreach_color_swatch(label: rx.Var[str | int], color: rx.Var[str]):
    return rx.box(
        rx.text(label, color="white", weight="medium"),
        bg=color,
        padding_y="0.5em",
        padding_x="0.75em",
        min_width="5.5em",
        text_align="center",
        border_radius="0.375rem",
    )


def foreach_colored_box(color: rx.Var[str]):
    return foreach_color_swatch(color, color)


rx.grid(
    rx.foreach(ForeachColorState.colors, foreach_colored_box),
    columns="2",
    spacing="2",
)

The color the function receives is not a Python string but an rx.Var[str]. So you can put it straight into children or props (bg=color), but you can't use a Python if or string methods on it (use rx.cond for conditions).

Try it yourself

rx.foreach has no styling props. Change the list instead. Click a badge to remove that item; Add adds a new one. To pass an item's value to an event, write on_click=State.remove(f).

applebanana

2 items

FOREACH_FRUIT_POOL = ["apple", "banana", "cherry", "grape", "kiwi", "mango", "pear", "plum"]


class ForeachLiveState(rx.State):
    fruits: list[str] = ["apple", "banana"]

    @rx.event
    def add(self):
        for f in FOREACH_FRUIT_POOL:
            if f not in self.fruits:
                self.fruits.append(f)
                return

    @rx.event
    def remove(self, fruit: str):
        if fruit in self.fruits:
            self.fruits.remove(fruit)

    @rx.event
    def reset_fruits(self):
        self.fruits = ["apple", "banana"]


rx.vstack(
    rx.hstack(
        rx.foreach(
            ForeachLiveState.fruits,
            lambda f: rx.badge(f, rx.icon("x", size=12), on_click=ForeachLiveState.remove(f), cursor="pointer", size="2"),
        ),
        wrap="wrap",
    ),
    rx.hstack(
        rx.button("Add", on_click=ForeachLiveState.add, size="1"),
        rx.button("Reset", on_click=ForeachLiveState.reset_fruits, size="1", variant="soft", color_scheme="gray"),
        rx.text(ForeachLiveState.fruits.length(), " items", size="1", color_scheme="gray"),
        align="center",
    ),
)
ArgumentValuesUse
first (iterable)list, tuple or dict VarWhat to loop over. Usually a State variable or computed var
second (render_fn)function (item) or (item, index)Builds a component from one item. The second argument is a zero-based index

Getting the index too

If the function takes two arguments, the second one is the index (rx.Var[int], starting at 0). The color box reuses foreach_color_swatch from the first example (so does the dict example below).

0

1

2

3

class ForeachIndexState(rx.State):
    colors: list[str] = ["#E5484D", "#12A594", "#3E63DD", "#AD5700"]


def foreach_colored_box_index(color: rx.Var[str], index: rx.Var[int]):
    return foreach_color_swatch(index, color)


rx.grid(
    rx.foreach(ForeachIndexState.colors, lambda color, index: foreach_colored_box_index(color, index)),
    columns="2",
    spacing="2",
)

Nested lists

Use rx.foreach inside another rx.foreach to draw a two-dimensional list. The State variable's type must then be written out all the way down, like list[list[str]]. Reflex needs to know the type of the inner items to loop over the sublists, and it catches mistakes before they turn into browser errors.

1
2
3
4
5
6
7
8
9
class ForeachNestedState(rx.State):
    numbers: list[list[str]] = [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]]


def foreach_display_row(row: rx.Var[list[str]]):
    return rx.hstack(
        rx.foreach(
            row,
            lambda item: rx.box(item, border=f"1px solid {rx.color('gray', 8)}", padding="0.5em", min_width="2.2em", text_align="center"),
        ),
    )


rx.vstack(rx.foreach(ForeachNestedState.numbers, foreach_display_row))

Looping over a dict

Pass a dict and the function receives one (key, value) pair. color[0] is the key and color[1] the value. Whatever the key's original type (here int), inside the function it arrives as a string.

1

2

3

class ForeachSimpleDictState(rx.State):
    color_chart: dict[int, str] = {1: "#3E63DD", 2: "#E5484D", 3: "#12A594"}


def foreach_display_color(color: rx.Var[tuple[str, str]]):
    # color is a key-value pair such as ("1", "#3E63DD").
    return foreach_color_swatch(color[0], color[1])


rx.grid(
    rx.foreach(ForeachSimpleDictState.color_chart, foreach_display_color),
    columns="3",
    spacing="2",
)

For a dict whose values are lists, loop over the value again with rx.foreach. Below, each key color has its matching colors laid out underneath.

#8E4EC6

#E5484D

#3E63DD

#F76B15

#AD5700

#E5484D

#12A594

#3E63DD

#AD5700

class ForeachComplexDictState(rx.State):
    color_chart: dict[str, list[str]] = {
        "#8E4EC6": ["#E5484D", "#3E63DD"],
        "#F76B15": ["#AD5700", "#E5484D"],
        "#12A594": ["#3E63DD", "#AD5700"],
    }


def foreach_display_colors(color: rx.Var[tuple[str, list[str]]]):
    return rx.vstack(
        foreach_color_swatch(color[0], color[0]),
        rx.hstack(rx.foreach(color[1], lambda x: foreach_color_swatch(x, x))),
        align="center",
        spacing="2",
    )


rx.grid(
    rx.foreach(ForeachComplexDictState.color_chart, foreach_display_colors),
    columns="3",
    spacing="4",
)

Python comprehensions for constants

If the list is a constant that never changes, you don't need rx.foreach. Python can loop once when the page is built and lay out the components, and since the items are real Python values, you can use string methods and if.

SMLXL
rx.hstack(
    *[rx.badge(size, variant="soft") for size in ["S", "M", "L", "XL"]],
)

Filling the order

The tasks are a list of {"id", "text"} dicts (a list of dataclasses also works, as in the official docs). Giving each item key=item["id"] keeps the remaining rows intact when one is removed. Done passes the item's id to the handler, which builds a new list without that id. Input comes in through a form, so Enter adds a task too.

Todos

  1. Write Code

  2. Sleep

  3. Have Fun

class ForeachTodoState(rx.State):
    items: list[dict[str, str]] = [
        {"id": "1", "text": "Write Code"},
        {"id": "2", "text": "Sleep"},
        {"id": "3", "text": "Have Fun"},
    ]
    next_id: int = 4

    @rx.event
    def add_item(self, form_data: dict):
        text = form_data.get("new_item", "").strip()[:40]
        if text and len(self.items) < 8:
            self.items = self.items + [{"id": str(self.next_id), "text": text}]
            self.next_id += 1

    @rx.event
    def finish_item(self, item_id: str):
        self.items = [item for item in self.items if item["id"] != item_id]


rx.vstack(
    rx.heading("Todos", size="4"),
    rx.form(
        rx.hstack(
            rx.input(name="new_item", placeholder="Add a todo...", flex="1"),
            rx.button("Add", type="submit"),
            width="100%",
        ),
        on_submit=ForeachTodoState.add_item,
        reset_on_submit=True,
        width="100%",
    ),
    rx.divider(),
    rx.list.ordered(
        rx.foreach(
            ForeachTodoState.items,
            lambda item: rx.list.item(
                rx.hstack(
                    rx.button("Done", on_click=ForeachTodoState.finish_item(item["id"]), size="1", variant="soft"),
                    rx.text(item["text"]),
                    align="center",
                ),
                key=item["id"],
            ),
        ),
    ),
    width="100%",
    max_width="360px",
    padding="1em",
    border_radius="0.5em",
    background=rx.color("gray", 3),
)

Workshop notes

  • rx.foreach(State.items, function). For constant lists, use Python comprehensions.

  • The item the function receives is a Var. Use rx.cond instead of a Python if, and read values with item["key"].

  • (item, index) gives you the index too. A dict gives (key, value) pairs, and keys become strings.

  • For nested lists, write the type all the way down, like list[list[str]].

  • Give lists that add and remove items a key=unique value.

← Previous

Dynamic rendering · Match

Next →

Dynamic rendering · Auto Scroll

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