File uploader
Lets the reader pick files from their device, or drop them, and shows each one’s progress. It picks and lists files; uploading and checking them is the page’s, which reports back through each file’s status.
Live preview
Rendered by the component itself from the same generated tokens as the rest of the site.
Max file size is 500kb. Supported file types are .jpg and .png.
const [files, setFiles] = useState<UploaderFile[]>([])
<FileUploader
label="Upload files"
description="Max file size is 500kb. Supported file types are .jpg and .png."
accept=".jpg,.png"
files={files}
onAdd={(picked) => upload(picked)} // sets each file's status
onRemove={(id) => setFiles((f) => f.filter((x) => x.id !== id))}
/>Installation
Install it with the shadcn CLI, along with everything it uses. New project? Set it up first, as Quick start shows.
npx shadcn@latest add https://www.graphite-ui.com/r/file-uploader.jsonimport { FileUploader } from '@/components/ui/file-uploader'
import type { UploaderFile } from '@/components/ui/file-uploader'Anatomy
The label and a description of what may be uploaded, the trigger, then a list of the files, each with its name and a remove button. The list sits 16 under the trigger, its items 8 apart.
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- portrait-of-the-team-at-the-offsite.jpg
- LabelRequiredInput Label in on-surface (the kit's text-primary). Names the group.
- DescriptionOptionalThe kit's Desc. text, Body/3 in on-surface-variant, 8 under the label. Says what may be uploaded; the trigger is described by it.
- TriggerRequiredThe kit's Type. Default is the governed primary Button at the uploader's size; Drag and drop is a 100-tall drop box with a dashed edge, which is itself the file input's label.
- File listOptionalThe kit's Files. One item per file, 8 apart, each the private _File uploader file item.
Variants
Type is the trigger: a primary Button, or a drop box that also opens the picker. Size sets the Button and the file items, 48, 40 or 32; the drop box is 100 at every size.
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- portrait-of-the-team-at-the-offsite.jpg
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- portrait-of-the-team-at-the-offsite.jpg
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- portrait-of-the-team-at-the-offsite.jpg
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- portrait-of-the-team-at-the-offsite.jpg
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- portrait-of-the-team-at-the-offsite.jpg
States
Each file shows where it is: uploaded and removable, uploading, complete, or an error with its message, short or with a second line of detail. The drop box takes a 2px primary edge while files are over it or it has focus.
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- banner.jpg
- logo.png
- photo.jpgFile exceeds size limit.
- scan.pngFile exceeds size limit.500kb max file size. Select a new file and try again.
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- banner.jpg
- logo.png
- photo.jpgFile exceeds size limit.
- scan.pngFile exceeds size limit.500kb max file size. Select a new file and try again.
Max file size is 500kb. Supported file types are .jpg and .png.
- cover.png
- portrait-of-the-team-at-the-offsite.jpg
Max file size is 500kb. Supported file types are .jpg and .png.
API reference
Generated from the contract, versioned with it, and checked by drift-check. This table cannot describe props the component does not have.
| Prop | Type | Default | Notes |
|---|---|---|---|
| type | 'button' | 'dropzone' | — | The kit's Default and Drag and drop. |
| size | 'sm' | 'md' | 'lg' | — | The kit's Size. Sets the Button (32, 40, 48) and the file items (32, 40, 48). The drop box is 100 at every size, as the kit draws it. |
| label / description | — | — | The label is required. |
| buttonLabel / dropLabel | — | — | The trigger's copy. "Add file" and the kit's "Drag and drop files here or click to upload" by default. |
| accept / multiple | — | — | Passed to the file input. Multiple by default. |
| disabled | boolean | — | |
| files / onAdd / onRemove | — | — | Controlled. onAdd receives the files picked or dropped; uploading and validating them is the caller's, reported back through each file's status (uploaded, uploading, complete, error) and, for an error, error and errorDetail. |
Design tokens
Every swatch is live. Change the source color in the header and this table repaints, because it reads the same roles the component does.
on-surfaceThe label, file names and the remove glyph (Text/text-primary, Icon/icon-primary), and an Error long's first line.on-surface-variantThe description (Text/text-secondary).outlineThe drop box's dashed edge through the strong step (Border/border-strong-01), and the rule over an error message through the subtle step (Border/border-subtle-00).primaryThe drop box's copy (Link/link-primary), its drag-over and focus edge (Miscellaneous/interactive), the spinner, the remove glyph's focus ring through primary-focus, and the disabled family through primary-disabled and primary-disabled-content.elevationFile items, elevation-01 (Layer/layer-01).infoThe success mark (Support/support-info).dangerAn errored item's 2px edge, its status glyph and its message (Support/support-error, Text/text-error).backgroundThe mark inside the error glyph.textInput Label, Body/3, and Caption/1 for error messages.spacingThe 16 and 8 gaps, item padding and the drop box's padding.motionThe spinner's turn, through the indeterminate duration and its linear ease, as Modal's inline loading turns.
Usage
The contract's prohibitions, written as the choices you will actually face.
Do
- Say what may be uploaded in the description: size, type and how many.
- Show each file’s progress, and say what went wrong in the error, with what to do next in the detail.
- Use the drop box where uploading is the main task on the page.
- Let the reader remove a file they picked by mistake.
Don’t
- Show an error edge without its message.
- Upload on the reader’s behalf before they have chosen; picking is theirs.
- Restyle the Button. It is the governed primary Button.
- Hide the file types the picker accepts. Put them in the description too.
Accessibility
What the component does for you, and what it leaves to you.
- Roles
- A labelled group. The Default trigger is a Button that opens the native file picker; the drop box is the file input’s
label, so clicking or pressing it opens the same picker. - Keyboard
- Tab reaches the trigger and each remove button. Enter or Space on the trigger, or on the focused drop box, opens the picker.
- Names
- The trigger is described by the description. Each remove button is “Remove file”, described by the file’s error; uploading announces as a status.
- Focus
- The drop box takes a 2px
--graphite-primaryedge; the remove glyph a 2px--graphite-primary-focusring, 4 out. - Errors
- An errored file always shows its message, so the edge and the glyph never carry the meaning alone.
Figma parity
The kit’s File uploader page has one public set, with three private ones that draw the drop box and the file items. The code is one component; its file list is the private item, built in.
| Kit axis | Values | Code | How it maps |
|---|---|---|---|
| Type | Default · Drag and drop | type | button and dropzone. |
| Size | Large · Medium · Small | size | The Button at 48, 40 or 32 (the kit draws Large and Medium 2 over, as Button carries); the items at 48, 40 or 32. |
| State | Enabled · Disabled | disabled | The kit’s Disabled hides the file list, which reads as Files switched off; the code keeps the files, their remove buttons disabled. |
| State | Skeleton | — | No counterpart by rule. |
| Files | Boolean | files | The list shows when there are files. |
| Item state | Uploaded · Loading · Success · Focus · Error short · Error long | files[].status | uploaded, uploading, complete and error; error with errorDetail is Error long. Focus is the remove button’s pseudo-class. |
| Drop box | Enabled · Drag + Hover · Focus · Disabled | — | Drag-over is tracked while files are over it; focus is the file input’s. Disabled copy takes the disabled content tone, not the kit’s fill tone. |
| Remove glyph | Drop shadow | — | Read as a stray and not drawn. |
