Skip to main content
A styled drag-and-drop area for file uploads. Users can drop files onto it or click to browse — either way, the selected files are read client-side, converted to base64, and passed through the action system as $event. No server round-trip until you want one.
All file reading happens in the browser. Files are never sent to a server unless you explicitly wire up an action (like CallTool) to do so.
If you don’t need a dedicated upload area — say you just want an “Upload” button — see the OpenFilePicker action instead. It turns any clickable element into a file input.

Basic Usage

With no configuration, DropZone renders a full-width dashed upload area that accepts a single file of any type.

Customizing the Prompt

The label sets the primary prompt text and description adds secondary helper text below it — useful for hinting at accepted formats or size limits. You can also swap the default upload icon for any Lucide icon via the icon prop.

Accepted File Types

The accept parameter restricts which files the browser will allow. It works just like the HTML accept attribute — MIME types ("image/*"), extensions (".csv"), or a comma-separated mix of both.

Multiple Files

By default, DropZone accepts one file. Set multiple=True to let users select several at once — each new drop accumulates into the state array rather than replacing it.

Handling Uploads

Files stay in the browser until you do something with them. The on_change parameter fires actions when files are selected, with $event containing the file data — so the typical pattern is to pair it with a CallTool that sends the base64 payload to your MCP server for processing.
DropZone with CallTool
from prefab_ui.components import DropZone
from prefab_ui.actions.mcp import CallTool

DropZone(
    label="Upload CSV",
    accept=".csv",
    on_change=CallTool(
        "process_csv",
        arguments={"file": "{{ $event }}"},
    ),
)
Since on_change accepts a list, you can chain actions for UI feedback — show a loading state, call the tool, then clear the loading state:
DropZone with chained actions
from prefab_ui.components import DropZone
from prefab_ui.actions import SetState
from prefab_ui.actions.mcp import CallTool

DropZone(
    label="Upload data file",
    on_change=[
        SetState("uploading", True),
        CallTool("upload_file", arguments={"file": "{{ $event }}"}),
        SetState("uploading", False),
    ],
)

The FileUpload Type

Both DropZone and OpenFilePicker always produce $event as list[FileUpload] — an array of objects with name, size (bytes), type (MIME), and data (raw base64 — no data: URL prefix). Even single-file uploads produce a one-element array. Prefab ships a FileUpload type so you can annotate your MCP tool parameters with it:
Typing a tool parameter
from prefab_ui.actions import FileUpload

@server.tool()
def process_csv(files: list[FileUpload]):
    import base64
    for f in files:
        contents = base64.b64decode(f.data)
        # f.name, f.size, f.type also available
        ...

Disabled State

Reading the Value

DropZone stores selected file data in client state as list[FileUpload] — always an array, defaulting to []. Each entry has name, size (bytes), type (MIME), and data (base64) properties. With multiple=True, files accumulate across drops; with multiple=False, each upload replaces the previous one. Use .rx to reference file data in other components. The .length() pipe counts entries, and ForEach iterates over the array to display each file’s details. Drop some files below to see it work: Inside ForEach, the template variables $item.name, $item.type, and $item.size resolve to each file’s properties.

API Reference

DropZone Parameters

icon
str | None
default:"None"
Lucide icon name in kebab-case (e.g. "cloud-upload", "image"). Defaults to an upload icon.
label
str | None
default:"None"
Primary prompt text shown in the drop zone.
description
str | None
default:"None"
Secondary helper text below the label (e.g. file type hints).
accept
str | None
default:"None"
File type filter. Accepts MIME types ("image/*"), extensions (".csv"), or a comma-separated mix (".pdf,.docx,.txt").
multiple
bool
default:"False"
Allow selecting multiple files. When True, files accumulate across drops. When False, each upload overwrites the previous one.
max_size
int | None
default:"None"
Maximum file size in bytes per file. Files exceeding this are rejected with a toast notification.
disabled
bool
default:"False"
Whether the drop zone is non-interactive.
name
str | None
default:"None"
State key for auto-state binding. When set without on_change, file data is stored in state under this key.
on_change
Action | list[Action] | None
default:"None"
Action(s) to execute when files are selected. $event is always list[FileUpload].
css_class
str | None
default:"None"
Additional Tailwind CSS classes appended to the component’s built-in styles.

Protocol Reference

DropZone
{
  "type": "DropZone",
  "icon?": "string",
  "label?": "string",
  "description?": "string",
  "accept?": "string",
  "multiple?": false,
  "maxSize?": "number",
  "disabled?": false,
  "name?": "string",
  "onChange?": "Action | Action[]",
  "cssClass?": "string"
}
For the complete protocol schema, see DropZone.