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

Auto Scroll

rx.auto_scroll

Official docs

Workshop order

Build a customer support chat window. It should follow new messages down to the bottom, but not drag you down while you've scrolled up to read earlier messages.

rx.auto_scroll is a box (a div) that scrolls to the bottom by itself when new content is added. Use it for content that keeps piling up at the bottom, like chats, logs and feeds, so the newest item is always visible. You don't have to write any scroll-position code yourself.

Initial message
class AutoScrollBasicState(rx.State):
    messages: list[str] = ["Initial message"]
    count: int = 1

    @rx.event
    def add_message(self):
        self.count += 1
        self.messages = (self.messages + [f"New message #{self.count}"])[-50:]


rx.vstack(
    rx.auto_scroll(
        rx.foreach(
            AutoScrollBasicState.messages,
            lambda message: rx.box(
                message,
                padding="0.5em",
                border_bottom=f"1px solid {rx.color('gray', 4)}",
                width="100%",
            ),
        ),
        height="200px",
        width="300px",
        border=f"1px solid {rx.color('gray', 6)}",
        border_radius="8px",
    ),
    rx.button("Add Message", on_click=AutoScrollBasicState.add_message),
    width="300px",
    align_items="center",
)

Every click on Add Message adds a message, and once the box starts to overflow, it scrolls down by itself so the new message is visible.

Try the props

rx.auto_scroll is based on rx.el.div, so it accepts all div props and styles. Since it's a scroll box, height matters most. The box below holds twenty lines, yet the last line (Line 20) is visible from the start. Shrink the height to make it overflow and the bottom stays in view.

Try the props

Line 1

Line 2

Line 3

Line 4

Line 5

Line 6

Line 7

Line 8

Line 9

Line 10

Line 11

Line 12

Line 13

Line 14

Line 15

Line 16

Line 17

Line 18

Line 19

Line 20

height

padding

radius

rx.auto_scroll(
    *[rx.text("Line " + str(i), size="2") for i in range(1, 21)],
    height="160px",
    padding="8px",
    border_radius="8px",
    border=f"1px solid {rx.color('gray', 6)}",
    width="260px",
)
overflow="auto" is set by default, so content taller than the box scrolls inside it.
PropValuesDefaultUse
heightCSS lengthnoneHeight of the scroll box. Without it, the box grows with its content and never scrolls
widthCSS lengthnoneWidth
overflowCSS value"auto"How overflowing content is handled. Scrolls by default
padding, border, border_radiusCSS valuenoneInner spacing, border, corners
idstringautomaticIf you don't give one, a unique id is added automatically
other div propstitle, role, on_click …Same as rx.el.div

When to use it

  • Chat: keeps the conversation showing the latest message.
  • Log viewers: follows new log lines down as they appear.
  • Feeds: keeps new content visible in a list that keeps updating.

How it works

When content is added, it scrolls to the bottom in only two cases:

  1. The user is already near the bottom (within 50 pixels).
  2. There was no scrollbar before, and the new content created one.

So while the user has scrolled up to read earlier content, it doesn't force them down. Scroll the log box below up and press Add 10: the position stays put. Scroll back to the bottom and press it again, and it follows.

import random


class AutoScrollLogState(rx.State):
    lines: list[str] = []
    count: int = 0

    @rx.event
    def add(self, n: int):
        levels = ["INFO", "INFO", "INFO", "WARN", "ERROR"]
        new = []
        for _ in range(n):
            self.count += 1
            new.append(f"{self.count:04d} {random.choice(levels)} request handled")
        self.lines = (self.lines + new)[-100:]

    @rx.event
    def clear(self):
        self.lines = []
        self.count = 0


rx.vstack(
    rx.auto_scroll(
        rx.foreach(AutoScrollLogState.lines, lambda line: rx.text(line, size="1", font_family="var(--code-font-family)")),
        height="160px",
        width="100%",
        padding="8px 10px",
        background=rx.color("gray", 2),
        border=f"1px solid {rx.color('gray', 6)}",
        border_radius="8px",
    ),
    rx.hstack(
        rx.button("Add 1", on_click=AutoScrollLogState.add(1), size="1"),
        rx.button("Add 10", on_click=AutoScrollLogState.add(10), size="1", variant="soft"),
        rx.button("Clear", on_click=AutoScrollLogState.clear, size="1", variant="soft", color_scheme="gray"),
    ),
    width="100%",
    max_width="420px",
)

Filling the order

Giving rx.auto_scroll display="flex" and flex_direction="column" stacks the speech bubbles vertically, and rx.cond switches alignment and color depending on the sender. Sending a message adds both your message and the reply, and the window follows them down. If you've scrolled up to read, it stays where it is.

Hi! Ask me about your order.
class AutoScrollChatState(rx.State):
    messages: list[dict[str, str]] = [{"who": "bot", "text": "Hi! Ask me about your order."}]

    @rx.event
    def send(self, form_data: dict):
        text = form_data.get("text", "").strip()[:200]
        if not text:
            return
        reply = {"who": "bot", "text": f"Got it: {text}"}
        self.messages = (self.messages + [{"who": "me", "text": text}, reply])[-40:]


rx.vstack(
    rx.auto_scroll(
        rx.foreach(
            AutoScrollChatState.messages,
            lambda m: rx.flex(
                rx.box(
                    m["text"],
                    padding="6px 10px",
                    border_radius="12px",
                    max_width="80%",
                    background=rx.cond(m["who"] == "me", rx.color("indigo", 9), rx.color("gray", 4)),
                    color=rx.cond(m["who"] == "me", "white", rx.color("gray", 12)),
                ),
                justify=rx.cond(m["who"] == "me", "end", "start"),
                width="100%",
            ),
        ),
        display="flex",
        flex_direction="column",
        gap="6px",
        height="240px",
        width="100%",
        padding="10px",
        border=f"1px solid {rx.color('gray', 6)}",
        border_radius="10px",
    ),
    rx.form(
        rx.hstack(
            rx.input(name="text", placeholder="Type a message", flex="1", auto_complete=False),
            rx.button(rx.icon("send", size=16), type="submit", aria_label="Send"),
            width="100%",
        ),
        on_submit=AutoScrollChatState.send,
        reset_on_submit=True,
        width="100%",
    ),
    width="100%",
    max_width="360px",
)

Workshop notes

  • rx.auto_scroll(...) is a div that follows new content down to the bottom.

  • Always give it a height. overflow="auto" is set by default.

  • It scrolls down only when you are near the bottom (50px) or when a scrollbar newly appears.

  • It doesn't drag down users who have scrolled up to read. Ideal for chats, logs and feeds.

← Previous

Dynamic rendering · Foreach

Next →

Media · Image

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