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
Media

Video

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")

Try the props

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")
Turn controls off and the playback bar disappears. Then play it with the playing switch or a State button.
PropValuesDefaultUse
srcaddress, list of addresses, list of {"src": …, "type": …}noneThe video to play (file, YouTube, Vimeo …)
playingTrue / FalseFalsePlay / pause
controlsTrue / FalseTrueShows the playback bar
loopTrue / FalseFalseStarts over when it ends
volume0 ~ 11Volume
mutedTrue / FalseFalseMutes the sound. Required for autoplay
lightTrue / FalseFalseShows only a preview image instead of the player and opens the player on click
configdictnoneSettings per player type ({"youtube": {…}}, {"vimeo": {…}})
disable_remote_playbackTrue / FalseFalseTurns off playing on another device (casting)
width · heightCSS sizecontent sizePlayer 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.

Your own control bar

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",
)

YouTube and videos from other sites

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",
)

light: just a preview first

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.

Filling the order

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.

← Previous

Media · Audio

Next →

Tables and data grids · Table

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