Tessina UI
ConfiguratorGitHubIntroduction
InstallationUsageTheming
ComponentsAccordionAction SheetAlertAlertDialogArea ChartAspectRatioAvatarBadgeBannerBar ChartBottom NavBreadcrumbButtonButtonGroupCalendarCardCarouselChartChatBubbleCheckboxChipCodeBlockCollapsibleColor PickerComboboxCommandContainerContextMenuDate PickerDividerDrawerDropdown MenuEmptyStateFABFieldFieldsetFile UploadFile Upload 2FlexFormGridHoverCardIconButtonLabelLine ChartLinkMenubarMeterModalNavigation MenuNumberFieldOTP InputPaginationPie ChartPopoverProgressPromptInputRadar ChartRadial ChartRadioRatingScroll AreaSearchSegmentedControlSelectShortcutSidebarSkeletonSliderSpacerSpinnerSplit ButtonStackStatusStepperSurfaceSwitchTableTabsTextareaTime PickerToastToggleButtonToggleGroupToolbarTooltipTop Header DesktopTop Header Mobile
Contributing
Components

File Upload

Drag-and-drop file upload with file list, progress, validation, four visual variants, five sizes, intent colours, and per-file status (idle/uploading/success/error).

Playground

Installation

pnpm add @tessinaui/ui

Usage

import { FileUpload, FileUploadItem, FileUploadList } from "@tessinaui/ui";
{/* Single file */}
<FileUpload onValueChange={(files) => console.log(files)} />

{/* Multiple files */}
<FileUpload multiple maxFiles={5} />

{/* Restrict to images, 5 MB max */}
<FileUpload accept="image/*" maxSize={5 * 1024 * 1024} />

{/* Custom title / description / button */}
<FileUpload
  title="Front of your ID document"
  description="Drag and drop a file less than 5MB"
  actionLabel="Or select file"
/>

{/* Variants */}
<FileUpload variant="card" />
<FileUpload variant="dashed" />
<FileUpload variant="filled" />
<FileUpload variant="minimal" />

{/* Intents */}
<FileUpload intent="error" />
<FileUpload intent="success" />

{/* States */}
<FileUpload loading />
<FileUpload disabled />
<FileUpload skeleton />

{/* Controlled */}
<FileUpload value={files} onValueChange={setFiles} />

{/* Rejected file callback */}
<FileUpload
  maxSize={1024 * 1024}
  onFileRejected={(r) => alert(r.message)}
/>

Examples

Default

A single-file drop-zone with the default dashed variant.

Variants

Four visual styles — card, dashed, filled, and minimal.

Sizes

Padding and typography scale from sm through lg.

Intents

Colour intents tint the filled drop-zone for error, warning, success, and info.

States

Loading, disabled, and skeleton placeholder states.

File item states

Each list entry reflects its idle, uploading, success, or error status.

Variants

VariantDescription
cardSolid filled card surface — best for prominent primary upload zones
dashedDashed border drop-zone — the classic "drop files here" look
filledFilled background with a solid border — works well with intent tinting
minimalSolid 1px border, transparent background — discreet inline upload

Props

<FileUpload>

PropTypeDefaultDescription
acceptstring—Comma-separated MIME types or extensions (e.g. "image/*,.pdf")
maxSizenumber—Max bytes per file
maxFilesnumber1Max files in the list
multiplebooleanmaxFiles > 1Whether the file picker allows multi-select
valueUploadedFile[]—Controlled file list
defaultValueUploadedFile[][]Uncontrolled initial list
onValueChange(files) => void—Fires when the list changes
onFileAdded(file) => void—Fires per accepted file
onFileRejected(rejection) => void—Fires per file that fails validation (size / type / max-files)
onFileRemoved(file) => void—Fires when a file is removed
variantcard | dashed | filled | minimaldashedVisual style
sizexs | sm | md | lg | xlmdPadding / typography scale
intentnone | error | warning | success | infononeColour intent
roundednone | sm | md | lg | fulllgCorner radius
disabledbooleanfalseDisables the dropzone and picker
readOnlybooleanfalseDisables add/remove but renders normally
loadingbooleanfalseShows a spinner inside the dropzone with "Uploading…"
skeletonbooleanfalseRenders a pulse placeholder version
hideListbooleanfalseHide the file list rendered below
iconReactNode<Upload />Custom icon inside the circular badge
titleReactNode—Heading text
descriptionReactNode—Subtitle text
actionLabelReactNode"Or select file"Button label
dirltr | rtlltrText direction

<FileUploadItem>

PropTypeDescription
fileUploadedFileThe file metadata + status
sizeFileUploadSizeInherits from parent unless overridden
roundedFileUploadRoundedInherits from parent unless overridden
onRemove() => voidRemove button handler — pass undefined to hide it
onRetry() => voidRetry button handler — only visible in error status

UploadedFile

{
  id:        string;
  file:      File;
  name:      string;
  size:      number;
  type:      string;
  preview?:  string;            // object URL for images
  progress?: number;            // 0–100
  status?:   "idle" | "uploading" | "success" | "error";
  error?:    string;
}

File item states

The status of each entry in the list drives its appearance:

  • idle — file picked but no upload started; name + size + remove button
  • uploading — animated progress bar, percentage, and a spinner instead of the remove button
  • success — green check + "Uploaded"; remove still allowed
  • error — red alert + error message; retry button appears when onRetry is provided

Validation

FileUpload validates each incoming file against accept and maxSize. Rejected files don't enter the list — they fire onFileRejected with a { file, reason, message } payload where reason is one of:

  • "type" — extension or MIME type didn't match accept
  • "size" — file is larger than maxSize
  • "max-files" — adding would exceed maxFiles

Accessibility

  • The drop-zone is a role="button" with tabIndex={0} and a meaningful aria-label
  • Enter / Space opens the native file picker
  • Each item exposes aria-label="Remove file" / "Retry upload" on its action buttons
  • Object URLs created for image previews are revoked on unmount and on file removal

Fieldset

Groups related form controls under a shared legend, description, and helper text — built on Base UI's Fieldset primitive with four variants, five sizes, intent accents, and full RTL support.

File Upload 2

Dropzone-style file input. A native file input stretched across a dashed drop area — click anywhere or drag files onto it. Five sizes, five colour intents, five corner radii, RTL support, composed header/subheader/CTA lines, drag-over feedback, and a disabled state.

On this page

PlaygroundInstallationUsageExamplesDefaultVariantsSizesIntentsStatesFile item statesVariantsProps<FileUpload><FileUploadItem>UploadedFileFile item statesValidationAccessibility