Forms

Drag-and-drop file uploads

FileUpload wraps a visually hidden file input with a large hit target. Drag files over the surface to highlight the active state, or activate the native picker with keyboard and pointer.

Custom label

File upload code examples

Use Show output / Show code on each row. Snippets start with a Variant line naming the appearance.


Scenario: DEFAULT COPY · IMAGE ACCEPT


Scenario: ACTIVE STATE


Scenario: DISABLED


Scenario: ERROR STATE


Scenario: SUCCESS STATE


Scenario: WARNING STATE


Scenario: INFO STATE


Scenario: NEUTRAL STATE


Scenario: PURPLE STATE


Scenario: INDIGO STATE


Scenario: EMERALD STATE


Scenario: AMBER STATE


Scenario: PINK STATE


Scenario: ORANGE STATE


Scenario: TEAL STATE

CSS variable overrides

File upload CSS variables

Override these file upload variables on :root, a theme selector, or a component wrapper.

88 variables

Pattern: --zui-<component>-<slot?>-<variant?>-<property>-<state?>-dark?

:root {
  --zui-file-upload-ring-focus: oklch(70.2% 0.183 293.541 / 0.6);
  --zui-file-upload-ring-offset-focus: oklch(98.4% 0.003 247.858);
  --zui-file-upload-idle-border: #00000026;
  --zui-file-upload-idle-bg: #0000000d;
  --zui-file-upload-idle-fg: oklch(44.6% 0.043 257.281);
  --zui-file-upload-idle-border-hover: #00000040;
  --zui-file-upload-idle-bg-hover: #00000012;
  --zui-file-upload-active-border: oklch(70.2% 0.183 293.541 / 0.7);
  --zui-file-upload-active-bg: oklch(60.6% 0.25 292.717 / 0.1);
  --zui-file-upload-active-fg: oklch(20.8% 0.042 265.755);
  --zui-file-upload-error-border: oklch(70.4% 0.191 22.216 / 0.7);
  --zui-file-upload-error-bg: oklch(63.7% 0.237 25.331 / 0.1);
  --zui-file-upload-error-fg: oklch(57.7% 0.245 27.325);
  --zui-file-upload-error-border-hover: oklch(70.4% 0.191 22.216 / 0.8);
  --zui-file-upload-error-bg-hover: oklch(63.7% 0.237 25.331 / 0.15);
  --zui-file-upload-success-border: oklch(79.2% 0.209 151.711 / 0.7);
  --zui-file-upload-success-bg: oklch(72.3% 0.219 149.579 / 0.1);
  --zui-file-upload-success-fg: oklch(62.7% 0.194 149.214);
  --zui-file-upload-success-border-hover: oklch(79.2% 0.209 151.711 / 0.8);
  --zui-file-upload-success-bg-hover: oklch(72.3% 0.219 149.579 / 0.15);
  --zui-file-upload-warning-border: oklch(85.2% 0.199 91.936 / 0.7);
  --zui-file-upload-warning-bg: oklch(79.5% 0.184 86.047 / 0.1);
  --zui-file-upload-warning-fg: oklch(68.1% 0.162 75.834);
  --zui-file-upload-warning-border-hover: oklch(85.2% 0.199 91.936 / 0.8);
  --zui-file-upload-warning-bg-hover: oklch(79.5% 0.184 86.047 / 0.15);
  --zui-file-upload-info-border: oklch(70.7% 0.165 254.624 / 0.7);
  --zui-file-upload-info-bg: oklch(62.3% 0.214 259.815 / 0.1);
  --zui-file-upload-info-fg: oklch(54.6% 0.245 262.881);
  --zui-file-upload-info-border-hover: oklch(70.7% 0.165 254.624 / 0.8);
  --zui-file-upload-info-bg-hover: oklch(62.3% 0.214 259.815 / 0.15);
  --zui-file-upload-neutral-border: oklch(70.7% 0.022 261.325 / 0.7);
  --zui-file-upload-neutral-bg: oklch(55.1% 0.027 264.364 / 0.1);
  --zui-file-upload-neutral-fg: oklch(44.6% 0.03 256.802);
  --zui-file-upload-neutral-border-hover: oklch(70.7% 0.022 261.325 / 0.8);
  --zui-file-upload-neutral-bg-hover: oklch(55.1% 0.027 264.364 / 0.15);
  --zui-file-upload-purple-border: oklch(71.4% 0.203 305.504 / 0.7);
  --zui-file-upload-purple-bg: oklch(62.7% 0.265 303.9 / 0.1);
  --zui-file-upload-purple-fg: oklch(55.8% 0.288 302.321);
  --zui-file-upload-purple-border-hover: oklch(71.4% 0.203 305.504 / 0.8);
  --zui-file-upload-purple-bg-hover: oklch(62.7% 0.265 303.9 / 0.15);
  --zui-file-upload-indigo-border: oklch(67.3% 0.182 276.935 / 0.7);
  --zui-file-upload-indigo-bg: oklch(58.5% 0.233 277.117 / 0.1);
  --zui-file-upload-indigo-fg: oklch(51.1% 0.262 276.966);
  --zui-file-upload-indigo-border-hover: oklch(67.3% 0.182 276.935 / 0.8);
  --zui-file-upload-indigo-bg-hover: oklch(58.5% 0.233 277.117 / 0.15);
  --zui-file-upload-emerald-border: oklch(76.5% 0.177 163.223 / 0.7);
  --zui-file-upload-emerald-bg: oklch(69.6% 0.17 162.48 / 0.1);
  --zui-file-upload-emerald-fg: oklch(59.6% 0.145 163.225);
  --zui-file-upload-emerald-border-hover: oklch(76.5% 0.177 163.223 / 0.8);
  --zui-file-upload-emerald-bg-hover: oklch(69.6% 0.17 162.48 / 0.15);
  --zui-file-upload-amber-border: oklch(82.8% 0.189 84.429 / 0.7);
  --zui-file-upload-amber-bg: oklch(76.9% 0.188 70.08 / 0.1);
  --zui-file-upload-amber-fg: oklch(66.6% 0.179 58.318);
  --zui-file-upload-amber-border-hover: oklch(82.8% 0.189 84.429 / 0.8);
  --zui-file-upload-amber-bg-hover: oklch(76.9% 0.188 70.08 / 0.15);
  --zui-file-upload-pink-border: oklch(71.8% 0.202 349.761 / 0.7);
  --zui-file-upload-pink-bg: oklch(65.6% 0.241 354.308 / 0.1);
  --zui-file-upload-pink-fg: oklch(59.2% 0.249 0.584);
  --zui-file-upload-pink-border-hover: oklch(71.8% 0.202 349.761 / 0.8);
  --zui-file-upload-pink-bg-hover: oklch(65.6% 0.241 354.308 / 0.15);
  --zui-file-upload-orange-border: oklch(75% 0.183 55.934 / 0.7);
  --zui-file-upload-orange-bg: oklch(70.5% 0.213 47.604 / 0.1);
  --zui-file-upload-orange-fg: oklch(64.6% 0.222 41.116);
  --zui-file-upload-orange-border-hover: oklch(75% 0.183 55.934 / 0.8);
  --zui-file-upload-orange-bg-hover: oklch(70.5% 0.213 47.604 / 0.15);
  --zui-file-upload-teal-border: oklch(77.7% 0.152 181.912 / 0.7);
  --zui-file-upload-teal-bg: oklch(70.4% 0.14 182.503 / 0.1);
  --zui-file-upload-teal-fg: oklch(60% 0.118 184.704);
  --zui-file-upload-teal-border-hover: oklch(77.7% 0.152 181.912 / 0.8);
  --zui-file-upload-teal-bg-hover: oklch(70.4% 0.14 182.503 / 0.15);
}

/* Dark theme variables follow the same names with -dark appended. */
.dark {
  --zui-file-upload-ring-offset-focus-dark: oklch(12.9% 0.042 264.695);
  --zui-file-upload-idle-border-dark: #ffffff26;
  /* ...same variables with -dark at the end */
}

Overview

The component clears the native input value after each selection so selecting the same file twice still emits callbacks. Use accept and multiple to mirror platform constraints.

Common use cases

  • CSV and media imports in admin tools.
  • Profile and cover photo pickers.
  • Attachment surfaces on support forms.
  • Bulk asset ingestion during migrations.

FAQ

How do I handle selected files?

Use the onFiles callback to receive a File array. You can also listen to onChange for the underlying input event when integrating with form libraries.

Can I customize the inner content?

Yes. Pass children to replace the default helper copy while keeping the same focusable label wiring to the hidden input.