File
One file as a thing with a name: an attachment, an upload or a download.
On this page
A file is one document shown as a thing: a small page with its extension, the name over a quiet line of facts, and one control at the end. It is a flat sheet, so a column of files under a dropzone or inside a dialog reads as a stack of separate objects.
File
<ul class="flex flex-col gap-xs max-w(400) mx-auto"> <li class="file"> <span class="file-page" aria-hidden="true">pdf</span> <div class="file-body"> <p class="file-name">Q3 infrastructure report.pdf</p> <p class="file-meta">2.4 MB · PDF document</p> </div> <div class="file-end"> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Remove Q3 infrastructure report.pdf"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6L6 18" /> </svg> </button> </div> </li> <li class="file"> <img class="file-thumb" src="/demo/moonstone.svg" alt> <div class="file-body"> <p class="file-name">moonstone-cover.png</p> <p class="file-meta">1,920 × 1,200 · 840 KB</p> </div> <div class="file-end"> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Remove moonstone-cover.png"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6L6 18" /> </svg> </button> </div> </li> <li class="file"> <span class="file-page" aria-hidden="true">csv</span> <div class="file-body"> <p class="file-name">members-export-2026-11.csv</p> <p class="file-meta">312 rows · 18 KB</p> </div> <div class="file-end"> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Remove members-export-2026-11.csv"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6L6 18" /> </svg> </button> </div> </li></ul>#The page
file-page is a small raised sheet, 28 by 36, with the extension written at its foot in whatever case you type; it is set in capitals. Keep it to four characters. The name beside it already says the same thing, so hide the page from assistive technology with aria-hidden.
Its folded corner is drawn by the browser: with corner-shape, the top corner at the end is a bevel, and the flap is what that bevel leaves of a small square. A browser without corner-shape shows the page with four round corners and no fold.
When the file is a picture, file-thumb on an <img> takes the page's place.
#Uploading
Put a native <progress> with progress file-progress inside the file. The bar is then the sheet itself: it lies under the words from edge to edge and tints the sheet as far as the upload has come, and the sheet's corner finishes the fill. Without a value the amount is unknown and a band of the same tone travels across.
Write the amount in file-meta as well, and mark the file aria-busy="true" while it is on its way.
Uploading
<ul class="flex flex-col gap-xs max-w(400) mx-auto"> <li class="file" aria-busy="true"> <span class="file-page" aria-hidden="true">zip</span> <div class="file-body"> <p class="file-name">atlas-build-2026-11-11.zip</p> <p class="file-meta">Uploading · 64% of 182 MB</p> </div> <div class="file-end"> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Cancel the upload of atlas-build-2026-11-11.zip"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6L6 18" /> </svg> </button> </div> <progress class="progress file-progress" max="100" value="64" aria-label="Upload of atlas-build-2026-11-11.zip">64%</progress> </li> <li class="file" aria-busy="true"> <span class="file-page" aria-hidden="true">mp4</span> <div class="file-body"> <p class="file-name">onboarding-walkthrough.mp4</p> <p class="file-meta">Scanning for viruses…</p> </div> <progress class="progress file-progress" aria-label="Scan of onboarding-walkthrough.mp4"></progress> </li></ul>#Failed
file-failed gives the file the danger contour and turns file-meta to the danger ink. Say what went wrong there, and put the way out at the end. The state is a class because ARIA has no attribute for a failed item in a list: the words carry it, and role="alert" on them announces a failure that happens while the reader is on the page.
Failed
<div class="file file-failed max-w(400) mx-auto"> <span class="file-page" aria-hidden="true">mov</span> <div class="file-body"> <p class="file-name">walkthrough-final-v2.mov</p> <p class="file-meta" role="alert">Larger than the 100 MB limit</p> </div> <div class="file-end"> <button type="button" class="btn btn-sm">Replace</button> </div></div>#Compact
file-sm is one line, 32px tall and as wide as its name: an attachment above a composer, or a file mentioned in a row. It is as tall as a small button, so the two share a row. Its page is too small to carry the extension, so the name and the facts beside it do. The control at its end is 24px, 4px inside the sheet; on touch screens the file is 44px and the control 36px.
Compact
<form class="composer max-w(480) mx-auto"> <div class="composer-attachments"> <span class="file file-sm"> <span class="file-page" aria-hidden="true"></span> <span class="file-body"> <span class="file-name">report.pdf</span> <span class="file-meta">2.4 MB</span> </span> <span class="file-end"> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Remove report.pdf"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6L6 18" /> </svg> </button> </span> </span> <span class="file file-sm"> <img class="file-thumb" src="/demo/moonstone.svg" alt> <span class="file-body"> <span class="file-name">cover.png</span> </span> <span class="file-end"> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Remove cover.png"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6L6 18" /> </svg> </button> </span> </span> </div> <textarea class="composer-field" rows="1" placeholder="Add a note about these files" aria-label="Message"></textarea> <div class="composer-toolbar"> <div class="composer-end"> <button type="submit" class="btn btn-primary btn-sm">Send</button> </div> </div></form>#A file that opens
When the whole file is a link or a button, add file-interactive: it stands raised, lifts under the pointer and sinks when pressed, as a button does. Use <span> for the parts inside a link.
A file that opens
<div class="grid grid-cols(2) gap-sm max-w(520) mx-auto"> <a class="file file-interactive" href="#" download> <span class="file-page" aria-hidden="true">docx</span> <span class="file-body"> <span class="file-name">Master services agreement.docx</span> <span class="file-meta">48 KB · Download</span> </span> </a> <a class="file file-interactive" href="#" download> <span class="file-page" aria-hidden="true">xlsx</span> <span class="file-body"> <span class="file-name">Pricing schedule.xlsx</span> <span class="file-meta">22 KB · Download</span> </span> </a></div>#Accessibility
- Several files are a list: use
<ul>and putfileon each<li>. - A control's name says which file it acts on: "Remove report.pdf", not "Remove".
- Label the
<progress>, and keep the percentage in the text too: the tint is a drawing of it. - A long name is cut at the end. Put the full name in
titlewhen the ending matters, as with an extension.
#Classes
| Class | Description |
|---|---|
file | The flat sheet that holds the page, the words and the control |
file-failed | An upload that failed: the contour and file-meta take the danger ink; say the reason in file-meta. With file |
file-sm | One line, 32px tall like a small button and as wide as its name; the page is too small to carry the extension and a button inside is 24px, 4px in. With file |
file-interactive | The whole file is a link or a button: it stands raised, lifts under the pointer and sinks when pressed. With file |
file-page | The small page, 28 by 36, with the extension written at its foot in capitals |
file-thumb | A picture in the page's place, when the file is one |
file-body | The name and the line of facts under it |
file-name | The file's name, on one line that ends in an ellipsis |
file-meta | Size, kind, how far the upload is, or why it failed |
file-end | The control at the end: remove, retry or download |
file-progress | With progress on a progress element: the bar lies under the words and tints the sheet as far as the upload has come |
#Custom properties
| Property | Default | Description |
|---|---|---|
--file-padding | .625rem | Inset of the sheet; .375rem in a small file |
--file-radius | var(--radius-control-lg) | Corner of the sheet; var(--radius-control) in a small file |
--file-page-width | 1.75rem | Width of the page; 1rem in a small file |
--file-page-height | 2.25rem | Height of the page; 1.25rem in a small file |
--file-fold | .5625rem | Size of the folded corner; .3125rem in a small file |
#Related
- DropzoneA wide target for choosing or dropping files.
- ComposerWhere a message or a prompt is written: a growing field over a row of tools.
- ListRows of things with media, words and something at the end.