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.videoOfficial docs
Workshop order
In the photo slot of the vase product card, put a short intro video that plays silently and loops by itself.
rx.video is a player for video. Put the video's address in src. Besides video file addresses it also accepts addresses from sites such as YouTube and Vimeo. For test.mp4 in the assets folder it is src="/test.mp4". Under the hood it is react-player, the same part as rx.audio, so the props and events are exactly the same.
rx.video(src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4", width="400px", height="auto")playing, loop, muted and volume are all props you can drive with State values. Set the size with width and leave height="auto" to keep the video's original proportions.
Try the props
playing
loop
controls
muted
volume
0.8
width
rx.video(src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4", playing=False, loop=False, controls=True, muted=False, volume=0.8, width="400px", height="auto")| Prop | Values | Default | Use |
|---|---|---|---|
src | address, list of addresses, list of {"src": …, "type": …} | none | The video to play (file, YouTube, Vimeo …) |
playing | True / False | False | Play / pause |
controls | True / False | True | Shows the playback bar |
loop | True / False | False | Starts over when it ends |
volume | 0 ~ 1 | 1 | Volume |
muted | True / False | False | Mutes the sound. Required for autoplay |
light | True / False | False | Shows only a preview image instead of the player and opens the player on click |
config | dict | none | Settings per player type ({"youtube": {…}}, {"vimeo": {…}}) |
disable_remote_playback | True / False | False | Turns off playing on another device (casting) |
width · height | CSS size | content size | Player size |
The events are the same as Audio's: on_ready, on_start, on_play, on_playing, on_pause, on_waiting, on_ended, on_error, on_seeking, on_seeked (position, seconds), on_duration_change (duration, seconds), on_time_update (current position, seconds), on_progress ({played, playedSeconds, loaded, loadedSeconds, duration}), on_rate_change (playback rate), on_click_preview, on_enter_picture_in_picture, on_leave_picture_in_picture.
The official docs text says url="/test.mp4", but the prop name in 0.10 is src. Using url prints a warning and moves the value to src. Reflex sets controls to True by default.
Hide the default bar with controls=False, bind playing and muted to State values, and control them with buttons. on_duration_change gives the total length and on_time_update the current position, which fill a progress bar (rx.progress). on_time_update fires about 4 times a second, so slow it down with .throttle(500) before it goes to the server. This video starts muted.
0 / 0 s
Finished: 0
class VideoPlayerState(rx.State):
playing: bool = False
muted: bool = True
position: float = 0.0
duration: float = 0.0
finished: int = 0
@rx.var
def percent(self) -> int:
return int(self.position / self.duration * 100) if self.duration else 0
@rx.event
def toggle_play(self):
self.playing = not self.playing
@rx.event
def toggle_mute(self):
self.muted = not self.muted
@rx.event
def got_duration(self, seconds: float):
self.duration = round(seconds, 1)
@rx.event
def got_time(self, seconds: float):
self.position = round(seconds, 1)
@rx.event
def mark_ended(self):
self.playing = False
self.finished += 1
rx.vstack(
rx.video(
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
playing=VideoPlayerState.playing,
muted=VideoPlayerState.muted,
controls=False,
width="100%",
max_width="420px",
height="auto",
border_radius="8px",
overflow="hidden",
on_duration_change=VideoPlayerState.got_duration,
on_time_update=VideoPlayerState.got_time.throttle(500),
on_ended=VideoPlayerState.mark_ended,
),
rx.progress(value=VideoPlayerState.percent, max_width="420px"),
rx.flex(
rx.icon_button(
rx.cond(VideoPlayerState.playing, rx.icon("pause"), rx.icon("play")),
on_click=VideoPlayerState.toggle_play,
aria_label="Play or pause",
),
rx.icon_button(
rx.cond(VideoPlayerState.muted, rx.icon("volume-x"), rx.icon("volume-2")),
on_click=VideoPlayerState.toggle_mute,
variant="soft",
aria_label="Mute or unmute",
),
rx.text(VideoPlayerState.position, " / ", VideoPlayerState.duration, " s", size="2"),
rx.text("Finished: ", VideoPlayerState.finished, size="2", color_scheme="gray"),
spacing="3",
align="center",
),
width="100%",
spacing="3",
)Put a YouTube or Vimeo address in src and react-player loads that site's player to play it. Site-specific settings go under the matching key of config. This page shows it only as code so it does not load scripts from external sites.
rx.video(src="https://www.youtube.com/embed/9bZkp7q19f0", width="400px", height="auto")
rx.video(
src="https://www.youtube.com/watch?v=9bZkp7q19f0",
config={"youtube": {"color": "white"}},
width="400px",
height="225px",
)With light=True, only a preview image and a play button show at first, and the real player loads when clicked (on_click_preview). Use it to keep pages with many videos light. react-player fetches the preview image by asking an external service (noembed.com), so this page shows it only as code.
rx.video(src="https://www.youtube.com/watch?v=9bZkp7q19f0", light=True, width="400px", height="225px")To let users upload videos, see the Upload page.
Browsers block autoplay with sound but allow autoplay of videos with muted=True. So give playing=True, muted=True and loop=True together. Hide the playback bar and fill the top of the card with rx.inset.
Spring Bloom Vase
Hand-glazed ceramic, 24 cm
rx.card(
rx.inset(
rx.video(
src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
playing=True,
muted=True,
loop=True,
controls=False,
width="100%",
height="auto",
),
side="top",
pb="current",
),
rx.text("Spring Bloom Vase", weight="bold"),
rx.text("Hand-glazed ceramic, 24 cm", size="2", color_scheme="gray"),
max_width="320px",
)Workshop notes
rx.video(src="…"). Takes video files, assets paths (/test.mp4) and YouTube or Vimeo addresses.
width sets the size, height="auto" keeps the original proportions. controls defaults to True.
Autoplay is playing=True + muted=True. Looping is loop=True.
Your own control bar: controls=False + playing and muted in State + on_time_update (.throttle).
The prop name is src (url is the old name). Site-specific settings go in config, a light preview with light.
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.