Susegad UI
Register
Theme
Palette

Components

File drop

A native file input you can also drop files onto. Without JavaScript it is the browser's own input; with it, the real input covers a drop zone, and the element checks accept, size and count, lists each file with a Remove button, and says every change in words.

quiet warm playful

Open the live demo npx susegad add file-drop

Stands on: Core, Core: components, Tokens

The prompt

the prompt

Post your files: the letter goes into the box only when they are really kept.

A file input you can also drop files onto. Without JavaScript it is the browser's own file input and submits with the form. With it, the real input covers a drop zone. The element checks what the browser does not check on a drop, lists what was chosen, and says every change in words.

<link rel="stylesheet" href="susegad/components/file-drop/file-drop.css">
<script type="module" src="susegad/components/file-drop/file-drop.js"></script>

<form action="/send" method="post" enctype="multipart/form-data">
  <sg-file-drop max-size="10 MB">
    <label for="plans">Floor plans <span>PDF or JPG, up to 10 MB each</span></label>
    <input type="file" id="plans" name="plans" accept=".pdf,image/jpeg" multiple>
  </sg-file-drop>
</form>

The prompt

Build a file drop as a light-DOM custom element, <sg-file-drop max-size="10 MB">, around a native <label> and <input type=file>, so that without JavaScript it is the ordinary file input and the form sends the files. With JavaScript, move the label and input into a drop zone and stretch the input over the whole zone, transparent, so clicking, Enter and Space, and dropping onto it are all the browser's own, and show the input's focus on the zone. Also catch drops on the rest of the zone and put the files into the input itself, so the form still sends them. After every change, check what the browser does not check on a drop: the accept list read as the browser reads it, a size limit, and one file for an input without multiple. Keep what may stay by rebuilding the input's file list, and say in a status line what happened: "2 files chosen" and, for anything turned away, "setup.exe isn't a PDF or JPG, so it wasn't added." List each file with its size in words and a Remove button named for the file, and move focus to the next Remove button (or the input) when one goes. Give it three registers. Quiet: a dashed hairline zone that turns solid while a file is dragged over it, and nothing moves. Warm: a small pillar post box beside the words, with a letter waiting above the slot. It lifts to the slot while a file is dragged over, and is posted through the slot only when files are really kept, clipped so it vanishes at the slot. A turned-away file makes it shake. Playful: the letter drops in faster, the box gives a little as it lands, and three short marks say thunk. With reduced motion, change states without animation.

Words to code

When you sayTechniqueWhat happens
stretch the input over the whole zone, transparentnative firstThe real input lies over the zone with opacity 0. Every click, key and drop on it is the browser's own, and it stays in the form.
put the files into the input itselfinput.filesA drop elsewhere on the zone sets input.files = event.dataTransfer.files and fires change, so the form sends exactly what is listed.
the accept list read as the browser reads itpure matchingExtensions, image/* wildcards and exact types, ignoring case, in a pure function tested in Node. The browser's picker filters by accept; a drop does not, so the element does.
keep what may stay by rebuilding the input's file listDataTransferA new DataTransfer() holds the files that pass, and its files replaces the input's.
say in a status line what happenedlive regionOne role="status" line: the count, then a sentence for each file turned away, in the person's terms ("a PDF or JPG", "over 10 MB").
clipped so it vanishes at the slotSVG clip pathThe letter is clipped to the area above the slot. It slides down in front of the box and disappears exactly as it passes into it.
only when files are really keptmotion that follows the workThe letter is posted on a real change that kept at least one file, never on a timer or on hover alone.

<sg-file-drop> is a file input that also takes dropped files, checks them, lists them, and still works as a plain file input without JavaScript.

Usage

<link rel="stylesheet" href="susegad/components/file-drop/file-drop.css">
<script type="module" src="susegad/components/file-drop/file-drop.js"></script>

<form action="/send" method="post" enctype="multipart/form-data">
  <sg-file-drop max-size="5 MB">
    <label for="id">Photo ID <span>One photo, JPG or PNG, up to 5 MB</span></label>
    <input type="file" id="id" name="id" accept="image/jpeg,image/png" required>
  </sg-file-drop>
  <button>Send</button>
</form>

Put a <label for> and an <input type="file"> inside. Everything about what may be sent lives on the input: accept, multiple, required, name. The form sends the files the normal way.

Attributes, properties and events

NameWhat it does
max-sizeThe largest file allowed, like 10 MB, 500 KB or a number of bytes. Larger files are turned away with a sentence saying so.
handoffFor pages that take files the moment they arrive, like an uploader. The zone hands each choice or drop to the page and posts the letter; the page does the checking, listing and saying (the file-upload recipe uses its field note and progress list).
registerquiet, warm or playful; overrides the page's register.
remove(i) (method)Removes the file at index i.
sg-files (event)Fires after every change, with detail: { files, messages }.

Say the limits in the label's hint as well, for example "PDF or JPG, up to 10 MB each". The element also checks them, and says so if a file doesn't fit.

Registers

  • Quiet: a dashed hairline zone that turns solid while you drag a file over it. Nothing moves.
  • Warm: a pillar post box. The letter lifts to the slot while you drag a file over, and is posted when files are kept.
  • Playful: the letter drops in with a thunk.
  • Reduced motion: the states change without animation.

Accessibility

  • Without JavaScript it is the native file input, labelled by your label.
  • With JavaScript it is still the native input, stretched over the zone, so Tab reaches it, Space or Enter opens the file chooser, and the label names it. The zone shows its focus ring.
  • One status line says how many files are chosen and why any were turned away.
  • Each file in the list has a Remove button named for it ("Remove plan.pdf"). Removing one moves focus to the next Remove button, or back to the input.
  • required works as usual: the form waits, and focus goes to the input.
  • The post box is aria-hidden.

What moves, and why

The letter is posted only when files are really kept. Nothing is uploaded until the form is sent, so the element says "chosen", not "uploaded".