Skip to content

Example: File Upload with Preview

Demonstrates ui.FileUpload — uploading an image and displaying a preview, or uploading a CSV and showing the first rows in a table.


file_upload.py
import fluxui as ui

app = ui.App("File Upload Demo")


@app.page("/")
def home(session):
    # State for image upload
    image_path = ui.state("")

    # State for CSV upload
    csv_rows   = ui.state([])
    csv_name   = ui.state("")
    csv_error  = ui.state("")

    def handle_image(paths: list[str]) -> None:
        if paths:
            image_path.set(paths[0])

    def handle_csv(paths: list[str]) -> None:
        if not paths:
            return
        path = paths[0]
        csv_name.set(path.split("/")[-1])
        csv_error.set("")
        try:
            import csv
            with open(path, newline="", encoding="utf-8") as f:
                reader = csv.DictReader(f)
                rows = [row for row in reader]
            csv_rows.set(rows[:20])       # show at most 20 rows
        except Exception as exc:
            csv_error.set(f"Could not parse CSV: {exc}")
            csv_rows.set([])

    with ui.Column(gap="var(--s-8)"):
        ui.Heading("File Upload Demo", level=1)

        # ── Image upload ─────────────────────────────────────────────────
        with ui.Card(title="Image upload", description="Upload any image file for a preview"):
            ui.FileUpload(
                prompt="Drop an image here or click to browse",
                accept="image/*",
                on_change=handle_image,
            )
            if image_path.value:
                ui.Divider()
                ui.Text("Preview:", variant="label")
                ui.Image(
                    lambda: f"/uploads/{image_path.value.split('/')[-1]}",
                    alt="Uploaded image",
                    width="100%",
                )
                ui.Text(lambda: f"Path: {image_path.value}", variant="caption")

        # ── CSV upload ───────────────────────────────────────────────────
        with ui.Card(title="CSV upload", description="Upload a CSV to preview the first 20 rows"):
            ui.FileUpload(
                prompt="Drop a .csv file here or click to browse",
                accept=".csv,text/csv",
                on_change=handle_csv,
            )

            if csv_error.value:
                ui.Alert(csv_error, variant="danger")

            if csv_rows.value:
                ui.Divider()
                ui.Text(
                    lambda: f"Showing first {len(csv_rows.value)} rows of {csv_name.value}",
                    variant="label",
                )
                ui.Table(
                    data=csv_rows,
                    striped=True,
                    hover=True,
                )

        # ── Multi-file upload ─────────────────────────────────────────────
        file_list = ui.list_state([])

        def handle_multi(paths: list[str]) -> None:
            for p in paths:
                file_list.value.append(p.split("/")[-1])

        with ui.Card(
            title="Multiple files",
            description="Select several files at once",
        ):
            ui.FileUpload(
                prompt="Drop files here or click to browse",
                multiple=True,
                on_change=handle_multi,
            )
            if file_list.value:
                ui.Divider()
                ui.Text("Uploaded files:", variant="label")
                for fname in file_list.value:
                    with ui.Row(gap="var(--s-2)", align="center"):
                        ui.Badge("✓", variant="success")
                        ui.Text(fname)


if __name__ == "__main__":
    app.run(port=8000)

How It Works

  1. The browser sends the selected file(s) via an HTTP POST /upload request.
  2. FluxUI saves each file to a per-session temporary directory on the server.
  3. The server-side paths are passed to on_change as list[str].
  4. Your handler reads, parses, or stores those paths however it likes.

Accessing uploaded files

Use pathlib.Path(paths[0]).read_bytes() to get the raw bytes, or pass the path directly to pandas.read_csv(), PIL.Image.open(), etc.


Run it

pip install fluxui
python file_upload.py