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
Data display

Moment

rx.momentrx.MomentDelta

Official docs

Workshop order

Under each post in the review list, show when it was written as relative time, like '3 minutes ago' or '2 hours ago'. Hovering should reveal the exact time too.

rx.moment is a date display component that wraps react-moment. It formats dates the way you want and handles relative times like "5 minutes ago" and time zone conversion in the browser.

The examples on this page use date_now from the State below. It holds the time (UTC) when the server started; click "Update" and it changes to the current time, which every example below picks up. The Reflex docs keep a datetime in State as is, but here it is stored as an ISO string. rx.moment accepts both.

from datetime import datetime, timezone


class MomentDateState(rx.State):
    date_now: str = datetime.now(timezone.utc).isoformat()

    @rx.event
    def update_moment_date(self):
        self.date_now = datetime.now(timezone.utc).isoformat()


rx.vstack(
    rx.moment(MomentDateState.date_now),
    rx.button("Update", on_click=MomentDateState.update_moment_date, size="1", variant="soft"),
)

Try the props

format tokens follow moment.js rules (YYYY year, MM month, DD day, HH hour, mm minute, ss second, ddd weekday). Turn on from_now and relative time is shown instead of the format.

Try the props

format

tz

from_now

from_now_short

with_title

rx.moment("2026-01-01T09:00:00Z", format="YYYY-MM-DD HH:mm", tz="Asia/Seoul", from_now=False, from_now_short=False, with_title=False)
Change tz and the same moment is shown in that region's local time. Turn on with_title and hover to see the full date as a tooltip.
PropValuesUse
First argument / dateString, datetime, date …The date to show; without it, the current time
formatA format like "YYYY-MM-DD"Display format
from_now / to_nowTrue / FalseRelative time like "5 minutes ago" / "in 5 minutes"
from_now_shortTrue / FalseShort form like "1h", "2d"
from_now_duringMillisecondsRelative time only for that long, then format
add / subtractrx.MomentDelta(...)Adds or subtracts time for display only
tzA time zone like "Asia/Seoul"Show in that time zone
locale"fr" "ko" …Language of this component; default "en"
intervalMilliseconds (0 stops it)Re-render periodically
with_title / title_formatFull date shown on hover, and its format
diff · unit · decimalDifference between two dates
duration · duration_from_now · trimShow elapsed time
unix · parse · localHow to interpret the input date; output in local time
on_changeEventOn first appearance and whenever the date re-renders

Relative time

Often "how long ago" is easier to read than the date itself. from_now shows the time from now to that date ("2 hours ago"), and to_now the opposite direction ("in 2 hours"). from_now_short shortens it to something like "2h". With from_now_during=100000, relative time is shown for only 100 seconds, after which the date follows format.

from datetime import datetime, timezone


class MomentDateState(rx.State):
    date_now: str = datetime.now(timezone.utc).isoformat()

    @rx.event
    def update_moment_date(self):
        self.date_now = datetime.now(timezone.utc).isoformat()


rx.vstack(
    rx.moment(MomentDateState.date_now, from_now=True),
    rx.moment(MomentDateState.date_now, to_now=True),
    rx.moment("2026-01-01T09:00:00Z", from_now=True, from_now_short=True),
    rx.moment(MomentDateState.date_now, from_now_during=100000, format="YYYY-MM-DD HH:mm"),
)

Format

Shape the output however you like with format.

from datetime import datetime, timezone


class MomentDateState(rx.State):
    date_now: str = datetime.now(timezone.utc).isoformat()

    @rx.event
    def update_moment_date(self):
        self.date_now = datetime.now(timezone.utc).isoformat()


rx.vstack(
    rx.moment(MomentDateState.date_now, format="YYYY-MM-DD"),
    rx.moment(MomentDateState.date_now, format="HH:mm:ss"),
    rx.moment(MomentDateState.date_now, format="ddd, MMM D YYYY, h:mm A"),
)

Adding and subtracting time

Pass an rx.MomentDelta to add or subtract, and the date shifts only on screen while the State date stays as it is. The keys are years, quarters, months, weeks, days, hours, minutes and seconds, and Reflex 0.10 also has milliseconds. The left column adds 2 of each; the right column subtracts 2.

from datetime import datetime, timezone


class MomentDateState(rx.State):
    date_now: str = datetime.now(timezone.utc).isoformat()

    @rx.event
    def update_moment_date(self):
        self.date_now = datetime.now(timezone.utc).isoformat()


rx.grid(
    *[
        rx.moment(MomentDateState.date_now, add=rx.MomentDelta(**{unit: 2}), format="YYYY-MM-DD - HH:mm:ss")
        for unit in ["years", "quarters", "months", "weeks", "days", "hours", "minutes", "seconds"]
    ],
    *[
        rx.moment(MomentDateState.date_now, subtract=rx.MomentDelta(**{unit: 2}), format="YYYY-MM-DD - HH:mm:ss")
        for unit in ["years", "quarters", "months", "weeks", "days", "hours", "minutes", "seconds"]
    ],
    rows="8",
    flow="column",
    column_gap="6",
    row_gap="1",
    width="max-content",
)

Language

rx.moment defaults to English, and only a component given a locale switches to that language. Other components and pages are unaffected. A fixed language name loads only that language file; a State value loads all language files.

from datetime import datetime, timezone


class MomentDateState(rx.State):
    date_now: str = datetime.now(timezone.utc).isoformat()

    @rx.event
    def update_moment_date(self):
        self.date_now = datetime.now(timezone.utc).isoformat()


rx.vstack(
    rx.moment(MomentDateState.date_now, format="dddd D MMMM YYYY"),
    rx.moment(MomentDateState.date_now, format="dddd D MMMM YYYY", locale="fr"),
    rx.moment(MomentDateState.date_now, format="LL dddd", locale="ko"),
    rx.moment(MomentDateState.date_now, from_now=True, locale="ko"),
)

Time zones

With tz, the same moment is shown in that region's local time. z in the format is the time zone abbreviation.

from datetime import datetime, timezone


class MomentDateState(rx.State):
    date_now: str = datetime.now(timezone.utc).isoformat()

    @rx.event
    def update_moment_date(self):
        self.date_now = datetime.now(timezone.utc).isoformat()


rx.vstack(
    rx.moment(MomentDateState.date_now, tz="America/Los_Angeles", format="YYYY-MM-DD HH:mm z"),
    rx.moment(MomentDateState.date_now, tz="Europe/Paris", format="YYYY-MM-DD HH:mm z"),
    rx.moment(MomentDateState.date_now, tz="Asia/Seoul", format="YYYY-MM-DD HH:mm z"),
)

Re-rendering periodically in the browser

Without a date, it uses the browser's current time. Give it an interval (in milliseconds) and it re-renders at that interval, becoming a clock. It runs entirely in the browser without talking to the server.

rx.moment(interval=1000, format="HH:mm:ss")

on_change

on_change fires when the component first appears and every time the date re-renders, passing the date string. Even with interval=0, which means no periodic re-rendering, it fires once on first appearance. It fires again when the component reappears after a refresh or navigation, and in dev mode it may fire twice at first because of React Strict Mode. Turn on the switch and it fires every 2 seconds.

on_change fired 0 times

class MomentTickState(rx.State):
    updating: bool = False
    ticks: int = 0
    last: str = ""

    @rx.event
    def on_moment_tick(self, date: str):
        self.ticks += 1
        self.last = date

    @rx.event
    def set_moment_updating(self, value: bool):
        self.updating = value


rx.vstack(
    rx.hstack(
        rx.moment(
            format="HH:mm:ss",
            interval=rx.cond(MomentTickState.updating, 2000, 0),
            on_change=MomentTickState.on_moment_tick,
        ),
        rx.switch(checked=MomentTickState.updating, on_change=MomentTickState.set_moment_updating),
        align="center",
    ),
    rx.text("on_change fired ", MomentTickState.ticks, " times", size="2"),
    rx.text(MomentTickState.last, size="1", color_scheme="gray"),
)

Other props

These features appear only in the official docs' props table. From the top: date difference (days), date difference (months, decimal), time elapsed between two times, time elapsed from that date until now, interpreting a Unix timestamp (seconds), reading with a given format (parse), and relative time that reveals the full date on hover.

from datetime import datetime, timezone


class MomentDateState(rx.State):
    date_now: str = datetime.now(timezone.utc).isoformat()

    @rx.event
    def update_moment_date(self):
        self.date_now = datetime.now(timezone.utc).isoformat()


rx.vstack(
    rx.moment("2026-10-24", diff="2026-01-01", unit="days"),
    rx.moment("2026-10-24", diff="2026-01-01", unit="months", decimal=True),
    rx.moment(date="2026-10-24T12:00:00Z", duration="2026-10-24T09:30:00Z"),
    rx.moment("2026-01-01T00:00:00Z", duration_from_now=True, interval=1000),
    rx.moment("1767225600", unix=True, format="YYYY-MM-DD"),
    rx.moment("24/10/2026", parse="DD/MM/YYYY", format="YYYY-MM-DD"),
    rx.moment(MomentDateState.date_now, from_now=True, with_title=True, title_format="YYYY-MM-DD HH:mm:ss"),
)

Filling the order

Put a small relative time under each review, and use with_title so hovering shows the exact time. With interval=30000, "a few seconds ago" updates on its own to "a minute ago" and so on every 30 seconds.

Jin left a review

from datetime import datetime, timezone


class MomentDateState(rx.State):
    date_now: str = datetime.now(timezone.utc).isoformat()

    @rx.event
    def update_moment_date(self):
        self.date_now = datetime.now(timezone.utc).isoformat()


rx.card(
    rx.hstack(
        rx.avatar(fallback="JK", size="3", radius="full"),
        rx.vstack(
            rx.text("Jin left a review", weight="bold", size="2"),
            rx.moment(
                MomentDateState.date_now,
                from_now=True,
                with_title=True,
                title_format="YYYY-MM-DD HH:mm",
                interval=30000,
                font_size="12px",
                color=rx.color("gray", 11),
            ),
            spacing="0",
        ),
        align="center",
    ),
    max_width="320px",
)

Workshop notes

  • Format with rx.moment(date, format="YYYY-MM-DD"); use from_now/to_now for relative time.

  • add/subtract=rx.MomentDelta(days=2) shifts the date for display only.

  • tz sets the time zone; locale sets the language for this component only (default English).

  • With no date and interval=1000, you get a browser clock. on_change also fires on first appearance.

← Previous

Data display · Scroll Area

Next →

Disclosure · Tabs

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