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
Forms

Slider

rx.slider

Official docs

Workshop order

Add a price range filter to the product list. Two handles pick the lowest and highest price, and the chosen range shows right away.

rx.slider is a bar with a handle you drag to pick a number within a range. Use it for numbers where the rough position matters more than the exact value: volume, brightness, a price range. Give it one value for one handle, or a list of two for a range slider.

rx.slider(default_value=40)

Try the props

Change max and step, then drag the handle. It moves in steps of step.

Try the props

max

100

step

1

size

variant

color

radius

high_contrast

disabled

rx.slider(default_value=40, max=100, step=1, size="2", variant="surface", color_scheme="indigo", radius="full", high_contrast=False, disabled=False)
By default min is 0, max is 100 and step is 1. radius only accepts none, small and full.
PropValuesDefaultUse
default_valuenumber / list of numbers[50]Initial value (uncontrolled). Two values make a range slider
valuelist of numbers / VarnoneControlled value. A [value] list even with a single handle
min, max, stepnumber0, 100, 1Range and step
orientation"horizontal" "vertical""horizontal"Direction
size"1" – "3""2"Thickness
variant"classic" "surface" "soft""surface"Look
color_scheme, radius, high_contrasttheme valueColor, corners ("none" "small" "full"), contrast
widthCSS length"100%"Width
name, disabledForm field name, disable
on_changeeventContinuously while dragging. Passes a list of values
on_value_commiteventOnce when the handle is released. Passes a list of values

Once on release: on_value_commit

on_value_commit fires once, the moment you release the handle. The value always arrives as a list such as [50], even with one handle, so take it out with value[0]. Since it doesn't call the server while you drag, it is lightweight.

50

class SliderCommitState(rx.State):
    value: int = 50

    @rx.event
    def set_end(self, value: list[int | float]):
        self.value = int(value[0])


rx.vstack(
    rx.heading(SliderCommitState.value, size="5"),
    rx.slider(default_value=50, on_value_commit=SliderCommitState.set_end),
    width="100%",
)

Range slider

Give default_value a list of two values and you get two handles. Both values must lie between min and max. The handler receives [start, end].

The official docs' example writes min_=0, but in 0.10 min_ is passed through as a CSS style and does not become the slider's minimum. Write the minimum as min=0.

25

75

class SliderRangeState(rx.State):
    value_start: int = 25
    value_end: int = 75

    @rx.event
    def set_end(self, value: list[int | float]):
        self.value_start = int(value[0])
        self.value_end = int(value[1])


rx.vstack(
    rx.hstack(
        rx.heading(SliderRangeState.value_start, size="5"),
        rx.heading(SliderRangeState.value_end, size="5"),
    ),
    rx.slider(
        default_value=[25, 75],
        min=0,
        max=100,
        size="1",
        on_value_commit=SliderRangeState.set_end,
    ),
    width="100%",
)

Continuously while dragging: on_change + throttle

on_change fires continuously while the handle moves. Left alone, that sends far too many events, so .throttle(100) makes it send at most once every 100 ms.

50

class SliderLiveState(rx.State):
    value: int = 50

    @rx.event
    def set_end(self, value: list[int | float]):
        self.value = int(value[0])


rx.vstack(
    rx.heading(SliderLiveState.value, size="5"),
    rx.slider(
        default_value=50,
        min=0,
        max=100,
        on_change=SliderLiveState.set_end.throttle(100),
    ),
    width="100%",
)

Controlled slider: value

Give value the State value wrapped in a list ([State.volume]) and the handle always shows that value. In that case the handle only moves if on_change updates the State. When a button changes the State, the handle moves too.

30

class SliderControlState(rx.State):
    volume: int = 30

    @rx.event
    def set_volume(self, value: list[int | float]):
        self.volume = int(value[0])

    @rx.event
    def mute(self):
        self.volume = 0


rx.hstack(
    rx.icon("volume-2", size=18),
    rx.slider(
        value=[SliderControlState.volume],
        on_change=SliderControlState.set_volume.throttle(100),
        max=100,
        step=5,
        flex="1",
    ),
    rx.text(SliderControlState.volume, size="2", min_width="2em"),
    rx.button("Mute", on_click=SliderControlState.mute, size="1", variant="soft"),
    width="100%",
    align="center",
)

Vertical sliders and steps

With orientation="vertical" the slider stands upright. A vertical slider needs a parent with a height to be visible, and giving it width="auto" instead of the default "100%" makes it take only as much room as the bar is thick. The third slider has step=2, so it only stops at 0, 2, 4 … 10.

rx.hstack(
    rx.slider(default_value=30, orientation="vertical", width="auto"),
    rx.slider(default_value=[20, 60], orientation="vertical", width="auto", color_scheme="green"),
    rx.slider(default_value=4, min=0, max=10, step=2, orientation="vertical", width="auto", color_scheme="orange"),
    height="140px",
    spacing="6",
)

Using it in a form

With a name, it goes into the form data as name: value. The value arrives as a string ("40"), so convert it with int() to use it as a number. A slider with two handles submits its value twice under the name name[], but in 0.10 form data is a dict, so only the last value with that name survives. For a range, reading it through the State is the reliable way.

Results:

{}
class SliderFormState(rx.State):
    form_data: dict = {}

    @rx.event
    def handle_submit(self, form_data: dict):
        self.form_data = form_data


rx.card(
    rx.vstack(
        rx.form.root(
            rx.hstack(
                rx.slider(default_value=40, name="slider"),
                rx.button("Submit", type="submit"),
                width="100%",
                align="center",
            ),
            on_submit=SliderFormState.handle_submit,
            reset_on_submit=True,
            width="100%",
        ),
        rx.divider(),
        rx.hstack(rx.text("Results:", weight="bold"), rx.badge(SliderFormState.form_data.to_string())),
        width="100%",
    ),
    width="100%",
    max_width="420px",
)

Filling the order

The two handles are controlled with value=[low, high], and on_change is throttled to 100 ms so the range display keeps up while you drag. With step=10, prices move in steps of 10.

Price

$20 - $80

$0

$200

class SliderPriceState(rx.State):
    low: int = 20
    high: int = 80

    @rx.event
    def set_price(self, value: list[int | float]):
        self.low, self.high = int(value[0]), int(value[1])


rx.card(
    rx.vstack(
        rx.hstack(
            rx.text("Price", weight="bold"),
            rx.spacer(),
            rx.badge("$", SliderPriceState.low, " - $", SliderPriceState.high, variant="soft"),
            width="100%",
        ),
        rx.slider(
            value=[SliderPriceState.low, SliderPriceState.high],
            on_change=SliderPriceState.set_price.throttle(100),
            min=0,
            max=200,
            step=10,
        ),
        rx.hstack(rx.text("$0", size="1"), rx.spacer(), rx.text("$200", size="1"), width="100%", color_scheme="gray"),
        width="100%",
    ),
    width="100%",
    max_width="360px",
)

Workshop notes

  • rx.slider(default_value=40). A list of two makes a range slider.

  • Handlers always receive a list of values. With one handle, use value[0].

  • Once on release: on_value_commit. While dragging: on_change + .throttle(100).

  • Control it with value=[State.x] + on_change. The minimum is min= (not min_).

  • In a form, the value arrives as a string, like name: "40".

← Previous

Forms · Select

Next →

Forms · Form

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