Form controls

File Upload
v1.1.2
Documentation Under Review

A flexible file upload component with drag-and-drop support, file validation, progress tracking, and customizable trigger coloration built for product applications.

Prefer AI-assisted development?

This documentation is available via the Catalyst MCP Server. Learn how to connect →

Catalyst File Upload wraps react-dropzone with a compound-component API and built-in Catalyst design tokens — giving you drag-and-drop, validation, progress tracking, and error recovery with zero boilerplate.

Preview

Installation

npm install @pmi/catalyst-file-upload
import {
  FileUploadDropzone,
  FileUploadDropzoneArea,
  FileUploadTrigger,
  FileUploadDescription,
  FileUploadMessage,
  FileUploadFileList,
  FileUploadFileListItem,
  FileUploadRemoveFile,
  FileUploadRetryFile,
  useFileUpload,
  useFileUploadFileListContext,
} from '@pmi/catalyst-file-upload';

Add the preset to your tailwind.config.ts:

import tailwindFileUploadPreset from '@pmi/catalyst-file-upload';

export default {
  presets: [tailwindFileUploadPreset],
  // ...
};

Variants

Background

Use coloration="background" on FileUploadTrigger to apply a subtle filled background to the dropzone area.

Preview

Background Coloration

With background coloration

Neutral

Use coloration="neutral" for a white (light) / dark-surface (dark) dropzone background.

Preview

Neutral Coloration

With neutral coloration

Danger

Set isInvalid on FileUploadDropzone to communicate a validation error — the trigger, description, and message all adopt red tones.

Preview

Error State

File upload failed

Disabled

Set disabled on FileUploadDropzone to prevent file selection and apply reduced-opacity styles.

Preview

Disabled State

Upload functionality is disabled

Common Patterns

Card Wrapper

Wrap the upload component in a Card for elevated visual hierarchy on content-rich pages.

Preview

Card Wrapper

Wrapped in a card container

Preview Image

Display uploaded images with aspect-ratio preview thumbnails and per-item progress bars.

Preview

Custom variants and composition

Custom default

Use unstyled on all components to remove default CVA classes, then apply your own styles via className or a custom wrapper.

Preview

Custom background

Use unstyled on FileUploadTrigger to remove the dashed border, then apply your own background styles.

Preview

Background Coloration

With background coloration

Custom Neutral

Use unstyled on FileUploadTrigger to remove the dashed border, then apply your own neutral background styles.

Preview

Neutral Coloration

With neutral coloration

Custom Danger

Set isInvalid on FileUploadDropzone to trigger error state, then use unstyled on FileUploadTrigger to remove the dashed border and apply your own error background styles.

Preview

Error State

File upload failed

Custom Disabled

Set disabled on FileUploadDropzone to trigger disabled state, then use unstyled on FileUploadTrigger to remove the dashed border and apply your own disabled background styles.

Preview

Disabled State

Upload functionality is disabled

Custom card wrapper

Wrap the upload component in a Card for elevated visual hierarchy, then use unstyled on all File Upload components to apply your own styles.

Preview

Card Wrapper

Wrapped in a card container

Custom preview image

Display uploaded images with aspect-ratio preview thumbnails and per-item progress bars, then use unstyled on all File Upload components to apply your own styles.

Preview

Custom preview image card

Display uploaded images with aspect-ratio preview thumbnails and per-item progress bars, then wrap the upload component in a Card for elevated visual hierarchy and use unstyled on all File Upload components to apply your own styles.

Preview

API Reference

File Upload is a compound component built on react-dropzone. The sections below summarize the API surface for each part.

FileUploadDropzone

The root context provider. Spread the return value of useFileUpload onto it and add isInvalid / disabled as needed.

Accepts all props returned by useFileUpload plus children. Forwards that state to all descendant components via context.

FileUploadTrigger

The dashed-border dropzone area. Renders a <label> wrapping a hidden <input type="file">.

Prop

Type

FileUploadDescription

Descriptive helper text displayed below the trigger (accepted types, size limits, etc.).

Accepts all standard <p> HTML attributes. The unstyled prop removes default CVA classes for full className override.

FileUploadMessage

Root-level validation / error message. Reads the dropzone's rootError from context and auto-renders when present.

Prop

Type

FileUploadFileList

Scrollable container for the list of uploaded file items.

Accepts all standard <ul> HTML attributes. The unstyled prop removes default CVA classes.

FileUploadFileListItem

Individual file row. Automatically derives isInvalid from file.status === 'error'.

Prop

Type

FileStatus

Prop

Type

FileUploadRemoveFile

Wrapper for the remove button. Use asChild to render your own Button component inside it.

Accepts all standard <button> HTML attributes plus asChild and unstyled.

FileUploadRetryFile

Wrapper for the retry button on failed uploads. Use asChild to render your own Button component inside it.

Accepts all standard <button> HTML attributes plus asChild and unstyled.

useFileUpload

Hook that wires react-dropzone with Catalyst's file-status reducer. Pass its return value to FileUploadDropzone.

const dropzone = useFileUpload({
  onDropFile: async (file: File) => {
    return { status: 'success', result: uploadedUrl };
    // or on failure:
    return { status: 'error', error: 'Upload failed.' };
  },
  validation: {
    accept: { 'image/*': ['.png', '.jpg', '.jpeg'] },
    maxSize: 10 * 1024 * 1024,
    maxFiles: 10,
  },
});

Returns fileStatuses, isInvalid, disabled, getInputProps, and other dropzone state.

useFileUploadFileListContext

Access per-item context inside a FileUploadFileListItem for remove / retry callbacks.

Returns onRemoveFile, onRetry, and canRetry.

Accessibility

File Upload is designed to meet WCAG 2.2 AA standards.

Keyboard Interactions

KeyAction
TabMoves focus to the hidden file input inside the trigger
SpaceOpens the native file picker when the trigger has focus
TabMoves focus through remove / retry buttons in the file list
EnterActivates the focused remove or retry button

ARIA

  • The hidden <input type="file"> receives aria-invalid and aria-describedby (pointing to FileUploadMessage) when isInvalid is true.
  • FileUploadTrigger sets aria-disabled on the <label> when the dropzone is disabled.
  • ProgressRoot in file list items must have aria-label and aria-valuenow set by the consumer to announce upload progress — see the composition examples above.
  • FileUploadFileMessage (the per-item message element) should be given className="sr-only" when its text is redundant with visible UI, as shown in the default example.
  • Catalyst adds the visual styling; react-dropzone provides the underlying drag-and-drop and keyboard accessibility semantics.

See the react-dropzone accessibility docs for inherited baseline behavior.

Choosing the Right Component

Use File Upload when users need to select or drop one or more files with progress feedback. Reach for a different primitive when:

If you need…Use instead
A simple inline text or number inputTextField
Rich text or long-form inputTextArea
A date or calendar selectionCalendar

On this page