File Upload
How the File Upload works with a keyboard and assistive tech, and where it stands against WCAG 2.2 AA.
The drop zone is a native <button> that opens a real <input type="file">, so dragging is never the only way to add a file. Each upload reports its progress as a progressbar, and every action on a file is a named button.
Keyboard#
Moves to the drop zone, then through each file's pause, resume, retry, cancel, delete and download buttons.
On the drop zone, opens the system file picker. On a file's button, runs that action.
Does the same as Enter, on release.
Closes the system file picker without adding anything. This is the platform's own dialog.
Semantics#
<button>A real button. Its text (Click to upload from device) and the size limit are its name and description.
Drop zone<input type="file">Hidden from the tab order and from assistive tech, because the button stands in for it. accept and multiple are passed through.
Alwaysaria-describedbyLinks the allowed types, the size limit or the error, so they are read with the button.
Hint or errorrole="progressbar"Named for the file, with its percentage, and aria-valuetext that adds Paused or Failed.
Uploadingaria-labelNamed for what they do. Name them for the file too where several are listed: Delete Q3 report.pdf.
File buttonsrole="alert"The reason a file failed is announced at once.
A failed filearia-live="polite"Adding and removing files is announced without interrupting.
List changesColour contrast#
Every variant and state has to meet WCAG 2.2 Level AA. Measure the colours as they land on screen: a translucent hover or press wash over whatever sits behind it.
Drop zone text · Rest, Hover, Drag over
The label in #2a2a2a and Upload in #005cf8 pass on every fill. The size-limit caption is #8f8f8f, 3.15:1 on #fcfcfc, and fails.
WCAG 1.4.3 Contrast (Minimum) ↗Drop zone edge · Rest
The dashed #f2f2f2 edge is barely visible. The zone is a button with a readable label, so the label, not the edge, shows it can be used.
WCAG 1.4.11 Non-text Contrast ↗Progress · Uploading
The #005cf8 bar against its track and the page. The percentage is also given as text beside it.
WCAG 1.4.11 Non-text Contrast ↗Status text · Failed, Uploaded
Error text is #ec0d33 (4.49:1 on white) and drops further where it is set at 80% opacity. The green Uploaded badge is #229a14 on #cbfac2, 3.16:1. Both are under 4.5:1.
WCAG 1.4.3 Contrast (Minimum) ↗Focus indicator · Focus visible
A 2px ring in #1a6ef8 off a white gap, on keyboard focus only. It measures 4.54:1 on white, so it clears 3:1 on every light surface the library uses.
WCAG 1.4.11 Non-text Contrast ↗WCAG 2.4.13 Focus Appearance ↗Measured contrast#
The drop zone's text and dashed edge against its own fill in each state, from the ds.css tokens: #fcfcfc at rest, white on hover, #ebf2ff while a file is dragged over; text is held to 4.5:1 and the dashed edge to 3:1. 5 of 12 pairs fall below their minimum (4.5:1 for text, 3:1 for graphics) and are marked in amber.
Motion#
- Progress bars and washes move over 180ms as the percentage changes, and the zone's fill over 150ms. All are turned off under prefers-reduced-motion.
- The buffering spinner steps round continuously while a file starts; under reduced motion it stays still, and the progress text still says Starting.
Checklist#
State the allowed types and the size limit in the caption, not only in accept, and reject other files with a reason.
The caption (#8f8f8f, 3.15:1) and the error text (4.49:1, less at 80% opacity) fall under 4.5:1 and need darker shades.
Name file buttons for their file when several files are listed, so Delete is not read five times with nothing to tell them apart.
Don't announce every percentage. The progressbar holds the value for anyone who asks; announce the start, a failure and the finish.
After a file is deleted, move focus to the next file's row, or back to the drop zone when the list is empty.
Icon buttons are 40px and 44px, over the 24px minimum.
