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

Image

Workshop order

Fill the top of the poster product card with the product photo, and add a button for viewing the other photos.

rx.image is the HTML <img> element that shows a picture. Put the image address in src. It can be an external address (https://…), or, for a file in the app's assets folder, a path starting with / such as /logo.png. Write a description in alt for people who cannot see the image.

A river between mountains
rx.image(src="https://picsum.photos/id/1015/400/250", alt="A river between mountains", width="240px", height="auto")

Try the props

rx.image takes style props just like Box. Set the size, then choose with object_fit how the picture fits its box.

Try the props

Sample photo

src

width

height

object_fit

radius

rx.image(src="https://picsum.photos/id/1015/400/250", alt="Sample photo", width="200px", height="auto", object_fit="cover", border_radius="8px")
Fix the height and the box no longer has the original's proportions. Then object_fit cover crops to fill, contain shrinks until everything shows, and fill stretches.
PropValuesDefaultUse
srcaddress, /assets path, State value, PIL imagenoneThe image to show. Passing it as the first child also sets src
altstringnoneImage description (for screen readers and when the image fails to load)
loading"eager" "lazy""eager"With "lazy", it downloads when it comes near the screen
decoding"async" "auto" "sync""auto"Whether to decode the image separately from painting the page
src_set · sizesstringnonePicks an image size that fits the screen width
cross_origin"anonymous" "use-credentials"noneHow CORS requests are made for images from other domains
referrer_policy"no-referrer" "origin" …noneWhich referrer to send when requesting the image
use_map"#map-name"noneLinks clickable areas on the image (<map>)
styleswidth height object_fit border_radius border …Styled with CSS props, like Box

It takes the standard events such as on_click.

Styling it like Box

Use style props such as border_radius, border and box_shadow as they are. A square image with border_radius="50%" becomes a circle. In 0.10, passing the address as the first child, as in the third image, also sets src.

A black puppyA pug in a blanketPositional src
rx.flex(
    rx.image(
        src="https://picsum.photos/id/237/300/300",
        alt="A black puppy",
        width="120px",
        height="auto",
        border_radius="15px 50px",
        border="5px solid #555",
    ),
    rx.image(
        src="https://picsum.photos/id/1025/300/300",
        alt="A pug in a blanket",
        width="120px",
        border_radius="50%",
        box_shadow="0 4px 14px rgba(0, 0, 0, 0.25)",
    ),
    rx.image("https://picsum.photos/id/1043/300/300", alt="Positional src", width="120px", border_radius="8px"),
    spacing="4",
    align="center",
    wrap="wrap",
)

Fitting the box: object_fit

Here a 400×250 image sits in a 160×160 box. cover keeps the proportions, fills the box and crops what spills over. contain keeps the proportions and shrinks the image until all of it shows, leaving empty space. fill ignores the proportions and stretches. When cells must match in size, as in a product list, cover is the usual choice.

covercover
containcontain
fillfill
rx.flex(
    rx.vstack(
        rx.image(src="https://picsum.photos/id/1039/400/250", alt="cover", width="160px", height="160px", object_fit="cover"),
        rx.code("cover"),
        align="center",
    ),
    rx.vstack(
        rx.image(src="https://picsum.photos/id/1039/400/250", alt="contain", width="160px", height="160px", object_fit="contain",
                 background=rx.color("gray", 4)),
        rx.code("contain"),
        align="center",
    ),
    rx.vstack(
        rx.image(src="https://picsum.photos/id/1039/400/250", alt="fill", width="160px", height="160px", object_fit="fill"),
        rx.code("fill"),
        align="center",
    ),
    spacing="4",
    wrap="wrap",
)

Images for the screen width, and lazy loading

List several sizes of the same image in src_set and tell the browser in sizes which width to use at which screen width, and it picks and downloads the right file. Narrow screens get the small file and load faster. loading="lazy" delays the download until the image comes near the screen.

Coffee being poured
rx.image(
    src="https://picsum.photos/id/1060/800/500",
    src_set="https://picsum.photos/id/1060/400/250 400w, https://picsum.photos/id/1060/800/500 800w",
    sizes="(max-width: 600px) 400px, 800px",
    alt="Coffee being poured",
    loading="lazy",
    decoding="async",
    width="100%",
    max_width="400px",
    border_radius="8px",
)

Changing the image from State

Put a State value in src and the image changes when the value does. Click a thumbnail below and the large image changes. The list of addresses lives in State, and only the selected index changes.

Selected photo
ThumbnailThumbnailThumbnailThumbnail
class ImageGalleryState(rx.State):
    photos: list[str] = [
        "https://picsum.photos/id/1015/480/300",
        "https://picsum.photos/id/1025/480/300",
        "https://picsum.photos/id/1043/480/300",
        "https://picsum.photos/id/1080/480/300",
    ]
    current: int = 0

    @rx.event
    def show(self, i: int):
        self.current = i


rx.vstack(
    rx.image(
        src=ImageGalleryState.photos[ImageGalleryState.current],
        alt="Selected photo",
        width="100%",
        max_width="480px",
        aspect_ratio="16 / 10",
        object_fit="cover",
        border_radius="8px",
    ),
    rx.flex(
        rx.foreach(
            ImageGalleryState.photos,
            lambda p, i: rx.image(
                src=p,
                alt="Thumbnail",
                width="72px",
                height="45px",
                object_fit="cover",
                border_radius="4px",
                cursor="pointer",
                opacity=rx.cond(i == ImageGalleryState.current, "1", "0.45"),
                on_click=ImageGalleryState.show(i),
            ),
        ),
        spacing="2",
    ),
    spacing="3",
)

App files and PIL images

Files in the app's assets folder are referenced with a path starting with /. You can also keep a Pillow (PIL) Image object in a State var and pass it to src; Reflex converts it to image data and sends it. Use this to show an image right after creating or editing it on the server. Pillow is not installed on this site, so it is shown only as code (it needs pip install pillow).

rx.image(src="/logo.png", alt="Logo", width="80px")   # assets/logo.png

from PIL import Image
import requests

class ImagePilState(rx.State):
    url: str = "https://picsum.photos/id/1/200/300"
    image: Image.Image = Image.open(requests.get(url, stream=True).raw)

def image_pil_example():
    return rx.image(src=ImagePilState.image, alt="Dynamically generated image")

rx.image only accepts addresses and PIL images. Convert an OpenCV (cv2) image to a PIL image, or save it as a file in the assets folder, before passing it. To let users upload images, see the Upload page.

Filling the order

rx.inset removes the card's top padding so the image fills the edge. Because the height is fixed, object_fit="cover" crops it to fit. The photo uses the same State as the gallery above, so clicking the button changes the photo in both examples.

Product photo

Mountain Trip Print

A3 poster, matte paper

rx.card(
    rx.inset(
        rx.image(
            src=ImageGalleryState.photos[ImageGalleryState.current],
            alt="Product photo",
            width="100%",
            height="180px",
            object_fit="cover",
            loading="lazy",
        ),
        side="top",
        pb="current",
    ),
    rx.text("Mountain Trip Print", weight="bold"),
    rx.text("A3 poster, matte paper", size="2", color_scheme="gray"),
    rx.button("Next photo", size="1", variant="soft", margin_top="8px",
              on_click=ImageGalleryState.show((ImageGalleryState.current + 1) % 4)),
    max_width="300px",
)

Workshop notes

  • rx.image(src="…", alt="…"). Takes external addresses, /assets paths, State values and PIL images.

  • Style it like Box: width, height, border_radius, border.

  • With a fixed cell size, object_fit="cover" crops to fill (contain shows everything).

  • src_set and sizes pick a file for the screen width; loading="lazy" delays loading.

  • Always write alt, for people who cannot see the image and for when it fails to load.

← Previous

Dynamic rendering · Auto Scroll

Next →

Media · Audio

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