Data Display & Media
File
One file — an attachment, an upload, a document on a record — with what it is, how big it is, and what can be done with it. A photograph shows itself; anything else shows a page marked with its kind and extension.
It follows an upload through: a bar while it goes, the reason and a retry when it fails, the size and a download once it lands. A long name is cut in the middle, so the extension stays in view.
Selecting the name fires nana-file-open; pair it with nana-file-viewer
to preview the file in place.
Preview
Section titled “Preview”<nana-file
name="Tenancy agreement - Unit 4B.pdf"
size="482133"
meta="Signed 1 Mar 2026"
src="/files/lease-4b.pdf"
removable
></nana-file>
<nana-file
name="meter-reading-october.jpg"
size="2400000"
status="uploading"
progress="42"
></nana-file>
<nana-file
name="rent-roll.xlsx"
size="88210"
status="error"
error="The connection dropped. Try again."
></nana-file> States
Section titled “States”<div
style="display: flex; flex-direction: column; gap: 0.5rem; max-width: 34rem"
>
<nana-file
name="meter-reading-october.jpg"
size="2400000"
status="uploading"
progress="42"
></nana-file>
<nana-file
name="rent-roll.xlsx"
size="88210"
status="error"
error="The connection dropped. Try again."
></nana-file>
<nana-file
name="Tenancy agreement - Unit 4B.pdf"
size="482133"
meta="Signed 1 Mar 2026"
src="/samples/tenancy-agreement.pdf"
removable
></nana-file>
</div> | Status | Shows | Offers |
|---|---|---|
uploading | A bar at progress, or a moving one while it is unknown | Cancel, as nana-file-remove |
error | error in red | Retry, as nana-file-retry |
ready | The size and meta | Download when there is a src, and remove with removable |
A photograph shows itself — from thumbnail if you have a small one, or
src. Anything else is a page marked with its extension and coloured by kind:
PDF red, spreadsheets green, documents blue, presentations orange, audio and
video purple, archives amber.
<div
style="
display: grid;
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
gap: 0.75rem;
"
>
<nana-file
variant="card"
name="Living room.jpg"
size="2100000"
src="https://images.pexels.com/photos/7060814/pexels-photo-7060814.jpeg?auto=compress&cs=tinysrgb&w=480"
></nana-file>
<nana-file variant="card" name="Inventory.docx" size="45120"></nana-file>
<nana-file variant="card" name="Rent roll.xlsx" size="88210"></nana-file>
<nana-file variant="card" name="Walkthrough.mp4" size="48000000"></nana-file>
</div> variant="card" suits a grid of photographs and documents; the default row
suits a list of attachments.
Opening a file
Section titled “Opening a file”The name is a button that fires nana-file-open with the file’s name,
src and type. Hand those to a File Viewer to
preview it without leaving the page:
const viewer = document.querySelector("nana-file-viewer[modal]");const files = [...document.querySelectorAll("nana-file")];
document.addEventListener("nana-file-open", (e) => { viewer.files = files.map(({ name, src, type, size }) => ({ name, src, type, size })); viewer.show(files.indexOf(e.target));});Installation
Section titled “Installation”npm install @nana-tec/ui-componentsOr copy the source in and own it:
npx @nana-tec/ui add fileimport "@nana-tec/ui-components/file";<nana-file name="Tenancy agreement - Unit 4B.pdf" size="482133" meta="Signed 1 Mar 2026" src="/files/lease-4b.pdf" removable></nana-file><nana-file name="meter-reading-october.jpg" size="2400000" status="uploading" progress="42"></nana-file><nana-file name="rent-roll.xlsx" size="88210" status="error" error="The connection dropped. Try again."></nana-file>const el = document.querySelector("nana-file");el.addEventListener("nana-file-open", (e) => console.log(e.detail));el.addEventListener("nana-file-remove", (e) => console.log(e.detail));el.addEventListener("nana-file-retry", (e) => console.log(e.detail));Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
error | error | string | '' | Why the upload failed |
meta | meta | string | '' | Details after the size, such as who uploaded it and when |
name | name | string | '' | The file's name, with its extension |
noDownload | no-download | boolean | false | Leave out the download link |
progress | progress | number | undefined | — | Upload progress, 0 to 100; leave unset while the size of the upload is unknown |
removable | removable | boolean | false | Offer to remove the file |
size | size | number | undefined | — | Size in bytes |
src | src | string | '' | Where the file can be opened or downloaded from |
status | status | FileStatus | 'ready' | Where the file has got to |
thumbnail | thumbnail | string | '' | A smaller image to show instead of loading src for a photograph |
type | type | string | '' | MIME type, when the name alone does not say what the file is |
variant | variant | FileVariant | 'row' | row for a list, card for a grid |
Events
| Event | Description |
|---|---|
nana-file-open | The file was chosen to open (detail.name, detail.src, detail.type) |
nana-file-remove | The reader asked to remove the file, or cancel its upload |
nana-file-retry | The reader asked to try a failed upload again |
Slots
| Slot | Description |
|---|---|
actions | Further controls beside the built-in ones |
CSS parts
| Part | Description |
|---|---|
::part(base) | The container |
::part(preview) | The thumbnail or file glyph |
::part(name) | The file name, a button that opens it |
::part(meta) | The size and details line, or the upload state |
::part(progress) | The upload bar |
::part(actions) | The controls |
::part(download) | The download link |
::part(remove) | The remove or cancel button |
::part(retry) | The retry button |
CSS custom properties
| Property | Description |
|---|---|
--nana-file-bg | Background |
--nana-file-border | Border colour |
--nana-press-scale | How far the buttons depress on press, shared with the other pressable controls |