Docs

Blog

Gallery

Resources

Learn

Components

API Reference

Onboarding

Library

/

Forms

/

Upload

The Upload component can be used to upload files to the server.

You can pass components as children to customize its appearance. You can upload files by clicking on the component or by dragging and dropping files onto it.

rx.upload(
    rx.text(
        "Drag and drop files here or click to select files"
    ),
    id="my_upload",
    border="1px dotted rgb(107,99,246)",
    padding="5em",
)

Selecting a file will add it to the browser's file list, which can be rendered on the frontend using the rx.selected_files(id) special Var. To clear the selected files, you can use another special Var rx.clear_selected_files(id) as an event handler. To upload the file, you need to bind an event handler and pass the file list.

A full example is shown below.

class State(rx.State):
    """The app state."""

    # The images to show.
    img: list[str]

    async def handle_upload(self, files: list[rx.UploadFile]):
        """Handle the upload of file(s).

        Args:
            files: The uploaded files.
        """
        for file in files:
            upload_data = await file.read()
            outfile = rx.get_upload_dir() / file.filename

            # Save the file.
            with outfile.open("wb") as file_object:
                file_object.write(upload_data)

            # Update the img var.
            self.img.append(file.filename)


color = "rgb(107,99,246)"


def index():
    """The main view."""
    return rx.vstack(
        rx.upload(
            rx.vstack(
                rx.button("Select File", color=color, bg="white", border=f"1px solid {color}"),
                rx.text("Drag and drop files here or click to select files"),
            ),
            id="upload1",
            border=f"1px dotted {color}",
            padding="5em",
        ),
        rx.hstack(rx.foreach(rx.selected_files("upload1"), rx.text)),
        rx.button(
            "Upload",
            on_click=State.handle_upload(rx.upload_files(upload_id="upload1")),
        ),
        rx.button(
            "Clear",
            on_click=rx.clear_selected_files("upload1"),
        ),
        rx.foreach(State.img, lambda img: rx.image(src=rx.get_upload_url(img))),
        padding="5em",
    )

In the example below, the upload component accepts a maximum number of 5 files of specific types. It also disables the use of the space or enter key in uploading files.

class State(rx.State):
    """The app state."""

    # The images to show.
    img: list[str]

    async def handle_upload(self, files: list[rx.UploadFile]):
        """Handle the upload of file(s).

        Args:
            files: The uploaded files.
        """
        for file in files:
            upload_data = await file.read()
            outfile = rx.get_upload_dir() / file.filename

            # Save the file.
            with outfile.open("wb") as file_object:
                file_object.write(upload_data)

            # Update the img var.
            self.img.append(file.filename)


color = "rgb(107,99,246)"


def index():
    """The main view."""
    return rx.vstack(
        rx.upload(
            rx.vstack(
                rx.button("Select File", color=color, bg="white", border=f"1px solid {color}"),
                rx.text("Drag and drop files here or click to select files"),
            ),
            id="upload2",
            multiple=True,
            accept = {
                "application/pdf": [".pdf"],
                "image/png": [".png"],
                "image/jpeg": [".jpg", ".jpeg"],
                "image/gif": [".gif"],
                "image/webp": [".webp"],
                "text/html": [".html", ".htm"],
            },
            max_files=5,
            disabled=False,
            on_keyboard=True,
            border=f"1px dotted {color}",
            padding="5em",
        ),
        rx.button(
            "Upload",
            on_click=State.handle_upload(rx.upload_files(upload_id="upload2")),
        ),
        rx.chakra.responsive_grid(
            rx.foreach(
                State.img,
                lambda img: rx.vstack(
                    rx.image(src=rx.get_upload_url(img)),
                    rx.text(img),
                ),
            ),
            columns=[2],
            spacing="5px",
        ),
        padding="5em",
    )

Your event handler should be an async function that accepts a single argument, files: list[UploadFile], which will contain FastAPI UploadFile instances. You can read the files and save them anywhere as shown in the example.

In your UI, you can bind the event handler to a trigger, such as a button on_click event, and pass in the files using rx.upload_files().

By convention, Reflex provides the function rx.get_upload_dir() to get the directory where uploaded files may be saved. The upload dir comes from the environment variable REFLEX_UPLOADED_FILES_DIR, or ./uploaded_files if not specified.

The backend of your app will mount this uploaded files directory on /_upload without restriction. Any files uploaded via this mechanism will automatically be publicly accessible. To get the URL for a file inside the upload dir, use the rx.get_upload_url(filename) function in a frontend component.

When using the Reflex hosting service, the uploaded files directory is not persistent and will be cleared on every deployment.

For persistent storage of uploaded files, it is recommended to use an external service, such as S3.

The id provided to the rx.upload component can be passed to the special event handler rx.cancel_upload(id) to stop uploading on demand. Cancellation can be triggered directly by a frontend event trigger, or it can be returned from a backend event handler.

The rx.upload_files special event arg also accepts an on_upload_progress event trigger which will be fired about every second during the upload operation to report the progress of the upload. This can be used to update a progress bar or other UI elements to show the user the progress of the upload.

class UploadExample(rx.State):
    uploading: bool = False
    progress: int = 0
    total_bytes: int = 0

    async def handle_upload(
        self, files: list[rx.UploadFile]
    ):
        for file in files:
            self.total_bytes += len(await file.read())

    def handle_upload_progress(self, progress: dict):
        self.uploading = True
        self.progress = round(progress["progress"] * 100)
        if self.progress >= 100:
            self.uploading = False

    def cancel_upload(self):
        self.uploading = False
        return rx.cancel_upload("upload3")


def upload_form():
    return rx.vstack(
        rx.upload(
            rx.text(
                "Drag and drop files here or click to select files"
            ),
            id="upload3",
            border="1px dotted rgb(107,99,246)",
            padding="5em",
        ),
        rx.vstack(
            rx.foreach(
                rx.selected_files("upload3"), rx.text
            )
        ),
        rx.progress(value=UploadExample.progress, max=100),
        rx.cond(
            ~UploadExample.uploading,
            rx.button(
                "Upload",
                on_click=UploadExample.handle_upload(
                    rx.upload_files(
                        upload_id="upload3",
                        on_upload_progress=UploadExample.handle_upload_progress,
                    ),
                ),
            ),
            rx.button(
                "Cancel",
                on_click=UploadExample.cancel_upload,
            ),
        ),
        rx.text(
            "Total bytes uploaded: ",
            UploadExample.total_bytes,
        ),
        align="center",
    )

The progress dictionary contains the following keys:

{
    'loaded': 36044800,
    'total': 54361908,
    'progress': 0.6630525183185255,
    'bytes': 20447232,
    'rate': None,
    'estimated': None,
    'event': {'isTrusted': True},
    'upload': True
}

A file upload component.

PropTypeDescriptionValues
acceptOptional

The list of accepted file types. This should be a dictionary of MIME types as keys and array of file formats as values. supported MIME types: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types

disabledbool

Whether the dropzone is disabled.

max_filesint

The maximum number of files that can be uploaded.

max_sizeint

The maximum file size (bytes) that can be uploaded.

min_sizeint

The minimum file size (bytes) that can be uploaded.

multiplebool

Whether to allow multiple files to be uploaded.

no_clickbool

Whether to disable click to upload.

no_dragbool

Whether to disable drag and drop.

no_keyboardbool

Whether to disable using the space/enter keys to upload.

Event Triggers

No component specific event triggers

← TextareaAreachart →

Did you find this useful?

HomeGalleryChangelogIntroductionHosting