File Upload

Upload files via drag-and-drop or file browser. Supports single and multiple files with progress indicators, previews, and validation.


Installation

File Upload uses Standard’s base styles and JavaScript for drag-and-drop interactions.

<link rel="stylesheet" href="/css/standard.css">
<script src="/js/standard.js" defer></script>

Usage

Basic Drop Zone

Click to upload or drag and drop

PNG, JPG, GIF up to 10MB

Multiple Files

Add multiple to accept multiple files.

Click to upload or drag and drop

Up to 5 files, 10MB each


Variants

Compact

Smaller drop zone for inline usage.

Upload file

With Border

More prominent border style.

Click to upload or drag and drop

SVG, PNG, JPG or GIF (max. 800x400px)

Image Preview

Shows thumbnail preview for uploaded images.

Preview

Change image

PNG, JPG up to 5MB


File List

Display uploaded files with actions.

Basic File List

Add more files

  • document.pdf 2.4 MB
  • photo.jpg 1.2 MB

With Progress

Show upload progress for each file.

  • large-video.mp4
    65% · 12.4 MB of 19.1 MB
  • report.pdf Complete · 4.2 MB
  • corrupted.zip Upload failed · File corrupted

States

Drag Over

Active state when files are dragged over the drop zone.

Drop files here

Disabled

Upload disabled

Contact admin for access

Error

File too large

Maximum file size is 10MB


Common Patterns

Profile Avatar Upload

JD

Profile Photo

JPG or PNG, max 2MB

Form with File Attachment

Attach files

Multi-file Upload with Progress

Upload files or drag and drop

  • design-v2.fig Complete · 8.1 MB
  • assets.zip
    40% · 3.2 MB of 8 MB

Customization

CSS Variables

.FileUpload {
  /* Dropzone */
  --file-upload-bg: var(--surface-1);
  --file-upload-border: var(--border-default);
  --file-upload-border-hover: var(--bd-s);
  --file-upload-border-active: var(--color-primary);
  --file-upload-radius: var(--radius-lg);
  --file-upload-padding: var(--space-8);

  /* Colors */
  --file-upload-icon-color: var(--text-muted);
  --file-upload-text-color: var(--text-default);
  --file-upload-hint-color: var(--text-muted);
  --file-upload-link-color: var(--color-primary);

  /* Progress */
  --file-upload-progress-bg: var(--surface-2);
  --file-upload-progress-fill: var(--color-primary);

  /* States */
  --file-upload-error-color: var(--color-error);
  --file-upload-success-color: var(--color-success);
}

Custom Styling Example

/* Circular avatar upload */
.FileUpload--avatar .FileUpload-dropzone {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  padding: var(--space-4);
}

.FileUpload--avatar .FileUpload-preview {
  border-radius: 50%;
  overflow: hidden;
}

API Reference

ClassDescription
.FileUploadBase container
.FileUpload--compactSmaller, inline variant
.FileUpload--borderedSolid border style
.FileUpload--previewImage preview layout
.FileUpload--disabledDisabled state
.FileUpload--errorError state
.FileUpload-dropzoneDrop target area
.FileUpload-dropzone.is-dragoverActive drag state
.FileUpload-inputHidden file input
.FileUpload-iconUpload icon
.FileUpload-textMain instruction text
.FileUpload-linkClickable upload trigger
.FileUpload-hintHelp text (file types, size)
.FileUpload-previewImage thumbnail container
.FileUpload-thumbnailPreview image
.FileUpload-listFile list container
.FileUpload-itemIndividual file row
.FileUpload-item--uploadingUpload in progress
.FileUpload-item--completeUpload complete
.FileUpload-item--errorUpload failed
.FileUpload-itemIconFile type icon
.FileUpload-itemInfoFile name and size container
.FileUpload-itemNameFile name
.FileUpload-itemSizeFile size / status
.FileUpload-progressProgress bar container
.FileUpload-progressBarProgress bar fill
.FileUpload-itemRemoveRemove/cancel button
.FileUpload-itemRetryRetry button

CSS Reference

/* Base container */
.FileUpload {
  width: 100%;
}

/* Dropzone */
.FileUpload-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-8);
  border: 2px dashed var(--bd);
  border-radius: var(--r-m);
  background: var(--bg);
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
  position: relative;
  text-align: center;
}

.FileUpload-dropzone:hover {
  border-color: var(--bd-s);
  background: var(--bg-s);
}

.FileUpload-dropzone.is-dragover {
  border-color: var(--accent);
  background: oklch(60% 0.15 250 / 0.05);
}

/* Hidden input */
.FileUpload-input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

/* Icon */
.FileUpload-icon {
  color: var(--fg-3);
}

/* Text */
.FileUpload-text {
  font-size: 0.9rem;
  color: var(--fg-2);
  margin: 0;
}

.FileUpload-link {
  color: var(--accent);
  font-weight: 500;
  cursor: pointer;
}

.FileUpload-hint {
  font-size: 0.8rem;
  color: var(--fg-3);
  margin: 0;
}

/* Compact variant */
.FileUpload--compact .FileUpload-dropzone {
  flex-direction: row;
  padding: var(--space-3) var(--space-4);
  gap: var(--space-3);
}

/* Bordered variant */
.FileUpload--bordered .FileUpload-dropzone {
  border-style: solid;
}

/* File list */
.FileUpload-list {
  list-style: none;
  padding: 0;
  margin: var(--space-3) 0 0;
}

.FileUpload-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--bd);
  border-radius: var(--r-s);
  margin-bottom: var(--space-2);
}

.FileUpload-itemIcon {
  flex-shrink: 0;
  color: var(--fg-3);
}

.FileUpload-itemIcon--success { color: oklch(55% 0.15 150); }
.FileUpload-itemIcon--error { color: oklch(55% 0.2 25); }

.FileUpload-itemInfo {
  flex: 1;
  min-width: 0;
}

.FileUpload-itemName {
  display: block;
  font-size: 0.9rem;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.FileUpload-itemSize {
  display: block;
  font-size: 0.8rem;
  color: var(--fg-3);
}

.FileUpload-itemSize--error {
  color: oklch(55% 0.2 25);
}

/* Progress bar */
.FileUpload-progress {
  height: 4px;
  background: var(--bg-s);
  border-radius: 2px;
  margin: var(--space-1) 0;
  overflow: hidden;
}

.FileUpload-progressBar {
  height: 100%;
  background: var(--accent);
  border-radius: 2px;
  transition: width 0.3s;
}

/* Remove / Retry buttons */
.FileUpload-itemRemove,
.FileUpload-itemRetry {
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  padding: var(--space-1);
  cursor: pointer;
  color: var(--fg-3);
  border-radius: var(--r-s);
  transition: background 0.15s;
}

.FileUpload-itemRemove:hover,
.FileUpload-itemRetry:hover {
  background: var(--bg-s);
  color: var(--fg);
}

/* States */
.FileUpload--disabled .FileUpload-dropzone {
  opacity: 0.5;
  pointer-events: none;
}

.FileUpload--error .FileUpload-dropzone {
  border-color: oklch(55% 0.2 25);
  background: oklch(55% 0.2 25 / 0.05);
}

/* Preview variant */
.FileUpload--preview .FileUpload-dropzone {
  flex-direction: row;
  text-align: left;
}

.FileUpload-thumbnail {
  width: 80px;
  height: 80px;
  object-fit: cover;
  border-radius: var(--r-s);
}

Accessibility

  • Use aria-label on remove/retry buttons
  • Add aria-describedby linking to hint text
  • Announce upload progress to screen readers via aria-live
  • Ensure keyboard access to drop zone via the file input
  • Provide clear error messages for validation failures

Keyboard Support

Key Action
Enter / Space Open file browser (when focused)
Delete Remove focused file from list
Tab Navigate between files and actions

Screen Reader Guidance

<div class="FileUpload">
    <div class="FileUpload-dropzone">
        <p class="FileUpload-text" id="upload-desc">
            <span class="FileUpload-link">Click to upload</span> or drag and drop
        </p>
        <p class="FileUpload-hint" id="upload-hint">PNG, JPG up to 10MB</p>
        <input type="file" class="FileUpload-input"
               aria-describedby="upload-desc upload-hint"
               aria-label="Upload file" />
    </div>
    <div aria-live="polite" class="sr-only">
        <!-- Announce upload progress and completion -->
    </div>
</div>

Best Practices

Do

  • Show accepted file types and size limits — Users need to know constraints before uploading
  • Display upload progress for large files — Visual feedback prevents uncertainty
  • Allow retry for failed uploads — Network errors happen; let users recover gracefully
  • Show image previews when appropriate — Helps users confirm they selected the right file
  • Provide clear error messages — “File exceeds 10MB limit” not just “Error”
  • Support drag-and-drop and click — Both interaction patterns are expected

Don’t

  • Allow uploads without size limits — Unbounded uploads risk server issues and poor UX
  • Remove files without confirmation — Accidental clicks shouldn’t lose uploaded work
  • Hide the file list when processing — Users need to see what’s happening
  • Use vague error messages — “Upload failed” tells users nothing actionable
  • Auto-upload on selection without user control — Let users review before submitting
  • Forget mobile touch targets — Drop zones and buttons must be at least 44px