Opening hours
Mon to Fri, 9 am to 6 pm.
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
rx.el.addressrx.el.articlerx.el.asiderx.el.blockquoterx.el.bodyrx.el.ddrx.el.del_rx.el.detailsrx.el.dialogrx.el.dlrx.el.dtrx.el.figcaptionrx.el.footerrx.el.h1 ~ h6rx.el.headrx.el.headerrx.el.hrrx.el.htmlrx.el.lirx.el.linkrx.el.mainrx.el.navrx.el.noscriptrx.el.olrx.el.portalrx.el.prerx.el.scriptrx.el.sectionrx.el.templaterx.el.titlerx.el.ulOfficial docs
Workshop order
Lay out one shop news post with meaningful HTML structure: a header, the body, a side tip, a collapsible question and a contact footer.
These HTML elements handle the structure and layout of a document. They include elements that name regions, like header, main and footer, the headings h1–h6, the lists ul, ol and dl, and the expandable details.
You could build the same look with divs, but meaningful elements let screen readers and search engines understand the structure of the page.
Mon to Fri, 9 am to 6 pm.
rx.el.article(
rx.el.header(rx.el.h2("Opening hours", font_weight="bold")),
rx.el.p("Mon to Fri, 9 am to 6 pm."),
rx.el.footer("Updated today", font_size="12px", color="gray"),
padding="12px",
border="1px solid gray",
border_radius="8px",
)Most structural elements only have common attributes. Play with the ones that have their own: ol (reversed) and details (open).
On this site Tailwind preflight removes list markers, so the markers are brought back with the CSS list_style_type.
Try the props
Shown when the details element is open.
reversed
marker
summary
open
rx.el.div(
rx.el.ol(
rx.el.li("Mix"),
rx.el.li("Bake"),
rx.el.li("Serve"),
reversed=False,
list_style_type="decimal",
padding_left="2em",
),
rx.el.details(
rx.el.summary("More info", cursor="pointer"),
rx.el.p("Shown when the details element is open."),
open=False,
),
)| Prop | Values | Default | Use |
|---|---|---|---|
start (ol) | integer | 1 | First number |
reversed (ol) | True / False | False | Count down |
type (ol) | "1" "a" "A" "i" "I" | "1" | Numbering style. With preflight, CSS list_style_type takes over |
open (details, dialog) | True / False | False | Expanded / open |
cite (blockquote, del_) | URL | none | Source of the quotation or edit |
date_time (del_) | date string | none | When the text was deleted |
rel href … (link) | string | none | Links an external resource (for the document head) |
async_ defer src … (script) | bool, string | none | Script tag (see the Script page) |
header is the head, nav the navigation menu, main the main content, article a piece that still makes sense on its own, aside a side note, section a thematic group, footer the bottom, and address the contact details.
They are all unstyled boxes, so the layout is set with CSS such as display="grid" or "flex".
The main story goes here.
A themed section of the page.
rx.el.div(
rx.el.header(
rx.el.strong("Workshop"),
rx.el.nav(rx.el.span("Home"), rx.el.span("Parts"), rx.el.span("About"), display="flex", gap="12px"),
display="flex",
justify_content="space-between",
padding="8px",
background=rx.color("indigo", 3),
),
rx.el.main(
rx.el.article(rx.el.h3("Post title", font_weight="bold"), rx.el.p("The main story goes here.")),
rx.el.aside("Related links", padding="8px", background=rx.color("gray", 3)),
display="grid",
grid_template_columns="2fr 1fr",
gap="12px",
padding="8px",
),
rx.el.section(rx.el.p("A themed section of the page."), padding="8px", border_top="1px dashed gray"),
rx.el.footer(rx.el.address("hello@example.com"), padding="8px", font_size="13px", color="gray"),
border="1px solid gray",
border_radius="8px",
overflow="hidden",
)Because of preflight, h1 and h3 come out the same size as body text. A heading is meaning; set its size separately with font_size.
hr is a line marking a change of topic, blockquote a long quotation (source in cite), and pre text that keeps its spaces and line breaks exactly.
The del element clashes with a Python keyword, so in Reflex it is written rx.el.del_ (the list in the official docs writes it as rx.el.Del). Its partner rx.el.ins marks newly inserted text.
Make it work, make it right, make it fast.
def hello():
print('hi')Price: $20 $15
rx.el.div(
rx.el.h1("h1 with no style"),
rx.el.h3("h3 with no style"),
rx.el.h2("h2 with style", font_size="24px", font_weight="bold"),
rx.el.hr(margin_y="8px"),
rx.el.blockquote(
"Make it work, make it right, make it fast.",
cite="https://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast",
border_left="4px solid gray",
padding_left="12px",
font_style="italic",
),
rx.el.pre("def hello():\n print('hi')", padding="8px", background=rx.color("gray", 3)),
rx.el.p("Price: ", rx.el.del_("$20", date_time="2026-10-01"), " ", rx.el.ins("$15")),
)ul is an unordered list and ol a numbered one, with li items. dl is a description list of term (dt) and description (dd) pairs.
rx.el.div(
rx.el.ul(rx.el.li("Apples"), rx.el.li("Pears"), list_style_type="disc", padding_left="1.5em"),
rx.el.ol(rx.el.li("Third"), rx.el.li("Fourth"), start=3, list_style_type="decimal", padding_left="1.5em"),
rx.el.dl(
rx.el.dt("Box", font_weight="bold"),
rx.el.dd("A container with no meaning.", margin_left="1.5em"),
rx.el.dt("Flex", font_weight="bold"),
rx.el.dd("A row or column of children.", margin_left="1.5em"),
),
display="flex",
gap="24px",
flex_wrap="wrap",
)The first summary inside details becomes its title, and clicking it makes the browser expand and collapse it on its own. No State needed.
dialog is opened with the open attribute. Opened this way it is a non-modal window that doesn't block what's behind it; for a modal dialog that covers the screen, rx.dialog is easier.
A box the browser opens and closes by itself.
class HtmlLayoutDialogState(rx.State):
is_open: bool = False
@rx.event
def toggle(self):
self.is_open = not self.is_open
rx.el.div(
rx.el.details(
rx.el.summary("What is details?", cursor="pointer"),
rx.el.p("A box the browser opens and closes by itself."),
),
rx.el.button(
"Toggle dialog",
on_click=HtmlLayoutDialogState.toggle,
padding="4px 12px",
border="1px solid gray",
border_radius="6px",
margin_top="12px",
),
rx.el.dialog(
rx.el.p("A non-modal dialog, opened by the open prop."),
open=HtmlLayoutDialogState.is_open,
padding="12px",
border="1px solid gray",
border_radius="8px",
top="40px",
),
position="relative",
min_height="150px",
)figcaption adds a caption to content inside a figure, such as an image, a table or code.
rx.el.figure(
rx.el.img(src="https://picsum.photos/id/1080/320/160", alt="Strawberries", border_radius="6px"),
rx.el.figcaption("Fig. 1 - Fresh strawberries", font_size="13px", color="gray", margin_top="4px"),
width="320px",
)Content inside template is not drawn on screen; it only remains as a template to clone. noscript only shows in browsers with JavaScript turned off. Reflex apps run on JavaScript, so it doesn't show here.
Only this line is visible.
rx.el.div(
rx.el.p("Only this line is visible."),
# rx.el.template(...) also keeps its content off the page, but React cannot
# hydrate children inside <template>, so it is left out of this live example.
rx.el.noscript("Please turn on JavaScript."),
)html, head, body, title, link, script and portal are elements for the whole document or its head. Reflex already builds this frame for you, so they are rarely used inside a page, and here they are shown as code only.
React 19 hoists title and link placed in the body up into the document head, so rendering them on a page would change this site's tab title.
# Document-level and head elements: Reflex already renders these, so pages rarely use them
rx.el.html(...) # manifest attribute (removed in HTML5)
rx.el.head(...)
rx.el.body(...)
rx.el.title("Page title") # set page titles with @rx.page(title=...)
rx.el.link(rel="stylesheet", href="/styles.css") # add stylesheets with rx.App(stylesheets=[...])
rx.el.script(src="/my-script.js") # use rx.script for scripts (see the Script page)
rx.el.portal(...) # experimental element that never became a standardThe whole post is an article, the title and date a header, the body a section, the tip an aside, the question a details, and the contact details an address inside the footer.
Three new dishes join the menu this week.
Yes, the soup and rolls are vegan.
rx.el.article(
rx.el.header(
rx.el.h1("Spring menu is here", font_size="22px", font_weight="bold"),
rx.el.p(rx.el.time("Mar 3, 2026", date_time="2026-03-03"), font_size="13px", color="gray"),
),
rx.el.section(
rx.el.p("Three new dishes join the menu this week."),
rx.el.ul(rx.el.li("Spring rolls"), rx.el.li("Pea soup"), rx.el.li("Lemon tart"), list_style_type="disc", padding_left="1.5em"),
margin_y="8px",
),
rx.el.aside("Tip: book a table early.", padding="8px", background=rx.color("amber", 3), border_radius="6px"),
rx.el.details(
rx.el.summary("Do you have vegan options?", cursor="pointer", font_weight="600"),
rx.el.p("Yes, the soup and rolls are vegan."),
margin_y="8px",
),
rx.el.hr(),
rx.el.footer(rx.el.address("12 Market St · hello@example.com"), font_size="13px", color="gray", margin_top="8px"),
padding="16px",
border="1px solid gray",
border_radius="10px",
max_width="420px",
)Workshop notes
header, nav, main, article, section, aside and footer name regions. Layout is done with CSS.
h1–h6 are only meaning. Under preflight, set the size with font_size.
ul, ol, li; dl, dt, dd. List markers via list_style_type; ol has start and reversed.
details + summary expands without State. dialog's open is non-modal; for a modal, use rx.dialog.
del is rx.el.del_. html, head, body, title and link are handled by Reflex, so don't use them in pages.
Get news about new lessons
We'll email you when this course gets new lessons or a follow-up course opens.
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© 2026 ReflexKR · Since 2026 · CC BY-NC 4.0
Questions & answers
Ask anything about this lesson. Questions from every language version of this page appear together.