Skip to content
Documentation

Forms

File upload

A drop zone for choosing files by dragging or browsing, with the chosen files listed below.

Needs dsgn.js components/file.css

Drop zone and chosen files

Attachments
  • invoice-2026-114.pdf120 kB
  • receipt.jpg40 %
Drop zone and chosen files
<div class="dsgn-stack" data-gap="s" style="max-inline-size: 32rem">
  <div class="dsgn-field">
    <span class="dsgn-label" id="dx-att-label">Attachments</span>
    <label class="dsgn-file">
      <input type="file" name="attachments" multiple accept=".pdf,image/*" aria-labelledby="dx-att-label dx-att-title" aria-describedby="dx-att-hint">
      <span class="dsgn-icon" aria-hidden="true">upload</span>
      <span class="dsgn-file-title" id="dx-att-title">Drop files here or <span class="dsgn-link">browse</span></span>
      <span class="dsgn-file-text" id="dx-att-hint">PDF, JPG or PNG, up to 10 MB each</span>
    </label>
  </div>
  <ul class="dsgn-list" aria-label="Chosen files">
    <li><div class="dsgn-list-item"><span class="dsgn-icon" aria-hidden="true">description</span><span class="dsgn-list-item-content"><span class="dsgn-list-item-title">invoice-2026-114.pdf</span><span class="dsgn-list-item-text">120 kB</span></span>
      <button class="dsgn-icon-button" data-variant="ghost" data-intent="neutral" aria-label="Remove invoice-2026-114.pdf"><span class="dsgn-icon" aria-hidden="true">close</span></button></div></li>
    <li><div class="dsgn-list-item"><span class="dsgn-icon" aria-hidden="true">image</span><span class="dsgn-list-item-content"><span class="dsgn-list-item-title">receipt.jpg</span><progress class="dsgn-progress" value="40" max="100" aria-label="Uploading receipt.jpg">40 %</progress></span>
      <button class="dsgn-icon-button" data-variant="ghost" data-intent="neutral" aria-label="Cancel upload of receipt.jpg"><span class="dsgn-icon" aria-hidden="true">close</span></button></div></li>
  </ul>
</div>

Usage

The real <input type="file"> stays in the page (keyboard, screen readers, form submit, mobile camera/gallery pickers); it is only visually hidden. The whole zone is the click target. dsgn.js adds drag and drop: while files are dragged over it the zone gets data-dragover, and dropped files go into the input (a change event fires, as if they were picked). Chosen files: render them under the zone as a List (static rows with a file icon, name, size or a Progress, and a remove icon button). Validate type and size on the server too. States: hover, keyboard focus (ring around the zone), drag over (accent), aria-invalid="true" on the input (danger outline; add a danger hint), disabled input.

Details

Classes
.dsgn-file .dsgn-icon .dsgn-file-title .dsgn-file-text .dsgn-link
Tokens used
--dsgn-border --dsgn-border-control --dsgn-border-width --dsgn-control-solid --dsgn-control-subtle --dsgn-control-text --dsgn-danger-solid --dsgn-duration-fast --dsgn-ease --dsgn-focus --dsgn-focus-danger --dsgn-focus-offset --dsgn-focus-width --dsgn-font-sans --dsgn-font-size-body-s --dsgn-font-size-caption --dsgn-font-weight-medium --dsgn-inset --dsgn-line-height-body-s --dsgn-line-height-caption --dsgn-line-height-heading --dsgn-neutral-subtle --dsgn-radius-l --dsgn-space-4 --dsgn-surface-raised --dsgn-text --dsgn-text-disabled --dsgn-text-muted
In Figma
File upload
Import alone
dsgn.systems/components/file.css