Skip to content
Nana UI

Data Display & Media

File Viewer

Looks at a file without leaving the page: a photograph to zoom into, a PDF in the browser's own reader, a video or a recording to play, a text file to read. A file the browser cannot draw — a Word document, a spreadsheet — says so plainly and offers the download instead of an empty frame.

View .md Download

Give it several files and it steps between them, with a strip of thumbnails underneath. It sits in the page by default; modal lifts it into a dialog over the page, opened and closed with open.

Arrow keys move between files. On a photograph + and - zoom, 0 resets, and once zoomed the arrows look around; Ctrl and the wheel, a pinch or a double click zoom too.

FileShown as
Photographs — JPEG, PNG, GIF, WebP, AVIF, SVGZoomable, with the arrows and drag to look around
PDFThe browser’s own PDF reader
Video and audioThe browser’s player
Text — TXT, JSON, Markdown, logsThe contents, up to 200 kB
Anything else — Word, Excel and CSV, HEIC, archivesThe file’s kind, a plain reason, and the download

modal puts the viewer in a native dialog over the page: focus stays inside, Escape closes it, and the page behind cannot be scrolled. Open it with show(index) or the open attribute; closing fires nana-viewer-close.

const viewer = document.querySelector("nana-file-viewer[modal]");
viewer.files = attachments;
viewer.show(2);

On a phone the dialog fills the screen.

Left and Right move between files. On a photograph, + and - zoom and 0 resets; once zoomed in, the arrows look around instead. Ctrl and the wheel, a pinch, or a double click zoom too. Inside a video or a PDF the keys belong to the player.

Photographs on this page are from Pexels.

npm install @nana-tec/ui-components

Or copy the source in and own it:

npx @nana-tec/ui add file-viewer
import "@nana-tec/ui-components/file-viewer";
<nana-file-viewer
files='[{"name":"Kitchen at move-out.jpg","src":"https://images.pexels.com/photos/17139803/pexels-photo-17139803.jpeg?auto=compress&cs=tinysrgb&w=1600","size":1840000,"meta":"Agent · 30 Sep"},
{"name":"Living room at move-in.jpg","src":"https://images.pexels.com/photos/7060814/pexels-photo-7060814.jpeg?auto=compress&cs=tinysrgb&w=1600","size":2100000},
{"name":"Rent roll.xlsx","src":"/files/rent-roll.xlsx","size":88210}]'
></nana-file-viewer>
const el = document.querySelector("nana-file-viewer");
el.addEventListener("nana-viewer-change", (e) => console.log(e.detail));
el.addEventListener("nana-viewer-close", (e) => console.log(e.detail));

Properties

PropertyAttributeTypeDefaultDescription
filesfilesFileItem[][]The files to look at: each a name and src, with type, size and meta if known
indexindexnumber0Which file is showing
modalmodalbooleanfalseShow the viewer in a dialog over the page
noDownloadno-downloadbooleanfalseLeave out the download link
noThumbnailsno-thumbnailsbooleanfalseLeave out the strip of thumbnails
openopenbooleanfalseWhether the modal viewer is open

Events

EventDescription
nana-viewer-changeAnother file was brought up (detail.index, detail.file)
nana-viewer-closeThe modal viewer was closed

Slots

SlotDescription
actionsFurther controls in the toolbar, such as a share or delete button

CSS parts

PartDescription
::part(base)The viewer
::part(toolbar)The bar over the file
::part(title)The file's name
::part(meta)The size and position line
::part(stage)Where the file is shown
::part(image)A photograph
::part(frame)The frame a PDF is shown in
::part(text)A text file's contents
::part(fallback)What is shown for a file with no preview
::part(thumbnails)The strip of files
::part(thumbnail)One file in the strip
::part(dialog)The native dialog, when modal

CSS custom properties

PropertyDescription
--nana-file-viewer-heightHeight of the stage when shown in the page
--nana-file-viewer-bgBackground behind the file
Explore File Viewer interactively Every state, prop, and edge case — with live controls — in Storybook.
View in Storybook