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
Other tools

Skeleton

rx.skeleton

Official docs

Workshop order

For the 1–2 seconds the profile card takes to load, show gray placeholders of the same size so the screen doesn't jump.

rx.skeleton is a gray placeholder shown in place of content while it loads. Wrap a child and it becomes a pulsing box the size of that child; when loading finishes, the real content appears in the same spot, so the layout doesn't shift. Without loading, it shows the placeholder.

rx.skeleton(rx.button("Loading button"))

Try the props

Turn off loading and the placeholder lifts to reveal the real content. An rx.skeleton without children gets its size from width and height.

Try the props

Grace Hopper

loading

title

width

height

rx.vstack(
    rx.flex(
        rx.skeleton(rx.avatar(fallback="RX", size="4"), loading=True),
        rx.box(
            rx.skeleton(rx.heading("Grace Hopper", size="3"), loading=True),
            rx.skeleton(rx.text("Posted two days ago.", size="2"), loading=True),
        ),
        rx.skeleton(rx.button("Follow"), loading=True),
        spacing="3",
        align="center",
    ),
    rx.skeleton(width="240px", height="24px", loading=True),
    spacing="4",
)
While loading is on, the button inside can't be clicked. The placeholder keeps the child's exact size, so turning it off doesn't move the layout.
PropValuesDefaultUse
loadingTrue / FalseTrueWhether to show the placeholder or the real content
width heightCSS length (responsive allowed)size of the childSize of the placeholder
min_width max_widthCSS lengthnoneMinimum / maximum width
min_height max_heightCSS lengthnoneMinimum / maximum height

Size and loading

This is the example from the official docs. The two placeholders wrapping buttons have their height changed with height, and the two below show loading set to True and to False.

Text is already loaded.

rx.vstack(
    rx.skeleton(rx.button("button-small"), height="10px"),
    rx.skeleton(rx.button("button-big"), height="20px"),
    rx.skeleton(rx.text("Text is loaded."), loading=True),
    rx.skeleton(rx.text("Text is already loaded."), loading=False),
)

Wrap the text itself

A placeholder for text wraps the text itself, not the parent around it. Wrap the parent and its full width turns gray; wrap the text and only the actual length of the text turns gray. Write it as rx.text(rx.skeleton("...")).

Wrap the parent:

Wrap the text itself:

rx.vstack(
    rx.text("Wrap the parent:", size="1", color_scheme="gray"),
    rx.skeleton(rx.box(rx.text("Short text"), width="100%")),
    rx.text("Wrap the text itself:", size="1", color_scheme="gray"),
    rx.text(rx.skeleton("Short text")),
    width="300px",
)

Giving the size directly

With no children and just width and height, you get an empty placeholder box. Use it to reserve space for lines, images or icons when you don't yet know what content will go there.

rx.vstack(
    rx.skeleton(width="240px", height="16px"),
    rx.skeleton(width="180px", height="16px"),
    rx.skeleton(width="100%", max_width="320px", height="80px"),
    rx.skeleton(width="48px", height="48px"),
    width="100%",
)

Filling the order

Click Reload and a background event turns loading on, waits 1.5 seconds and turns it off. Meanwhile the avatar, name and bio each turn into placeholders of their own size. The bio wraps the text inside rx.text, so only the length of the text turns gray.

Ada Lovelace

Wrote the first program.

import asyncio


class SkeletonProfileState(rx.State):
    loading: bool = False
    name: str = "Ada Lovelace"
    bio: str = "Wrote the first program."

    @rx.event(background=True)
    async def reload_profile(self):
        async with self:
            self.loading = True
        await asyncio.sleep(1.5)
        async with self:
            self.loading = False


rx.card(
    rx.flex(
        rx.skeleton(rx.avatar(fallback="AL", size="5", radius="full"), loading=SkeletonProfileState.loading),
        rx.box(
            rx.skeleton(rx.heading(SkeletonProfileState.name, size="4"), loading=SkeletonProfileState.loading),
            rx.text(rx.skeleton(SkeletonProfileState.bio, loading=SkeletonProfileState.loading), size="2", color_scheme="gray"),
        ),
        spacing="4",
        align="center",
    ),
    rx.button(
        "Reload",
        on_click=SkeletonProfileState.reload_profile,
        disabled=SkeletonProfileState.loading,
        variant="soft",
        margin_top="12px",
    ),
    max_width="360px",
)

Workshop notes

  • rx.skeleton(child) becomes a gray placeholder of exactly the child's size.

  • loading=False shows the real content. If not given, it shows the placeholder (True).

  • Wrap the text itself, not its parent: rx.text(rx.skeleton("...")).

  • Without children, reserve empty space with width and height.

  • While the placeholder shows, buttons and inputs inside can't be clicked.

← Previous

Other tools · Theme

Next →

Other tools · Clipboard

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