Asset Download
Asset Download renders a list of asset links — brochures, catalogues, PDFs. Each row is a single link naming the file as underlined text with the extension read inline, closing with one glyph; the file size sits on a second line beneath it. That trailing glyph is the whole cue: a download glyph for an <a download> that saves the file, an external-link glyph for a row that opens it in a new tab. Dividers between rows are drawn by Divider, which has first-class support for .tng-asset-download — no extra classes needed.
Usable — may still change
Asset Download is a list of one or more downloadable assets — brochures, catalogues, PDFs, images that the user is expected to save or read. Each row is a single link naming the file with the extension read inline (“Download brochure.pdf”), closing with one glyph, and drops the file size onto a second line under that link.
That trailing glyph says what the row does. A row that saves the asset to the device — a native <a download> — closes with a download glyph. A row that opens the asset in a new tab for the browser to render closes with an external-link glyph. Every row carries exactly one, so the glyph is read as a promise about the click rather than as decoration that some rows happen to have.
Anatomy
Section titled “Anatomy”- Asset download
- Row link
- Label
- Trailing glyph
- File size
Everything the user can click is one link — the filename and its trailing glyph. The row is a single target, so it costs a single tab stop, whether it saves the file or opens it.
The glyph sits inside that link, which is what keeps the two moving together: it takes the link’s colour and follows it through hover, active and visited rather than holding a colour of its own. It is decorative and never focusable, so being part of the target costs it nothing either. Only the file size sits outside the link — it colours independently and stays out of the link’s name.
When to use it
Section titled “When to use it”Use Asset Download when:
- A small set of supporting documents sits alongside primary content (vehicle brochures, technical specs, terms).
- The meaningful action is “save this file” and the file URL is consumer-supplied.
- The list lives inside the Alternate Content pattern where one pane lists downloads.
Avoid Asset Download when:
- The link should open a page rather than an asset — use a Link or Button with the URL instead. Opening a PDF in the browser is Asset Download’s own behaviour and needs no substitute.
- The list is long enough to need filtering, sorting, or pagination — that’s a Table or a custom list.
- The action triggers something other than a static asset download (for example dynamic generation). Asset Download leans on browser-native download; bespoke flows belong elsewhere.
Properties
Section titled “Properties”Label
The visible name of the asset, styled as a link — underlined, in link-button md type. The file extension reads inline as part of the name (“Download brochure.pdf”) rather than sitting in a separate muted span, so the link’s accessible name is the filename a user would recognise. Hover, active and visited states follow the Link treatment.
File size
The weight of the file, on a second line aligned under the label rather than beside it, in a subtler foreground. It sits outside the link — so it colours independently of the row’s link states, and it stays out of the link’s accessible name.
Trailing glyph
One glyph closes every row, and its shape is how a user tells the two behaviours apart before clicking: a download glyph for a row that saves the asset, an external-link glyph for a row that opens it in a new tab. Draw exactly one — never both, never neither, and never the shape that contradicts what the row does.
It sits inside the link as the Link’s trailing icon, so it takes the link’s colour and moves with it on hover, active and visited. It is not a second control: the row is one target. It is also not the whole cue for the new-tab case — that announcement is carried in the link’s accessible name, not by the glyph.
Divider
A thin line separates consecutive items and closes the list at both ends. The Divider component recognises .tng-asset-download directly, so the wrapping markup stays simple.
Platform considerations
Section titled “Platform considerations”Desktop
The full list is visible at once. Each row hugs its content, so the trailing glyph sits just after the filename rather than at the far edge — keep file names short enough to stay on one line and that grouping reads as a unit. Because the rows hug, the glyphs form no column: a reader compares two rows’ behaviour by reading each glyph next to its own name, which is why the shapes have to be distinct at a glance.
Tablet
The same stack works at narrower widths. The filename is the only part that shrinks, so the glyph stays tucked against the end of the name rather than drifting away from it.
Mobile
Long labels truncate with an ellipsis to keep the label on one line. Make sure the most identifying word leads so the truncation point stays useful — the extension now lives at the end of the name, and is the first thing an ellipsis eats.
Best practices
Section titled “Best practices”Use Asset Download for short, focused lists where the action is a file save — never as a generic link list.
Do
Let the file type pick the behaviour, then let the behaviour pick the glyph: <a download> with a download glyph for formats the user saves, target="_blank" with an external-link glyph for formats the browser can render. Keep labels short and meaningful, rely on the visible text for the accessible name, and announce the new tab whenever the row opens one. Keep everything clickable inside one link.
Don't
Don’t split the row across several links — a glyph that leads where the label leads is decoration, and giving it its own target only adds a tab stop. Don’t swap the two glyphs, ship a row with neither, or reinstate a leading glyph alongside the trailing one; the glyph is a promise about what the click does, and a second one only muddies it. Don’t pack the list with so many rows that it needs filtering, and don’t wire it to dynamic actions that aren’t a plain asset link.
Content guidelines
Section titled “Content guidelines”Write the label as the filename the user is about to open or save, extension included — “Download brochure.pdf”, “Owner’s manual.pdf”. The extension is not decoration here: it says in text what the trailing glyph says in shape, which is what keeps the preview-versus-save distinction off colour and shape alone. Never drop it or spell it out in prose instead. Lead with the most identifying word so the row scans at a glance and survives truncation, keep it short enough to fit on one line, and let the second line carry the size. Use sentence case, and don’t spell the format out twice (“Brochure PDF.pdf”) — the extension already tells that story.
.tng-asset-download wraps a <ul> of one or more downloadable assets, and each row carries .tng-asset-download-item. A row holds two children: the link that names the file, and the file size on a second line beneath it.
The link is a real Link: .is-neutral pins its rested colour, .is-md its type scale, and the underline, hover / active / visited colours and focus ring all come from the Link component. Wrap the filename in a <span> — that is the box .tng-overflow-ellipsis truncates. Only the file size stays outside the link, so it keeps its own colour and stays out of the link’s accessible name.
The trailing glyph goes inside the link, as the Link’s trailing icon. It needs no class of its own, and it takes the link’s colour and states for free. It is decorative — mark it aria-hidden="true".
Which glyph you draw follows what the row does, and every row draws one:
- Opens in a new tab —
target="_blank" rel="noopener noreferrer",icon-external-link, and a.sr-onlyspan so the new tab is announced. - Saves the file —
<a download>,icon-download, and nothing to announce.
In practice the file type picks between them: a PDF the browser can render opens in a new tab, everything else downloads. Both shapes sit in one list with no alignment work — the row hugs its content, so a shorter filename simply ends sooner.
<ul class="tng-asset-download" role="list"> <li class="tng-asset-download-item"> <a class="tng-link is-neutral is-md" href="#" target="_blank" rel="noopener noreferrer" > <span class="tng-overflow-ellipsis">Download brochure.pdf</span> <span class="sr-only">(opens in a new tab)</span> <i class="tng-icon icon-external-link" aria-hidden="true"></i> </a> <span class="tng-asset-download-meta">100 MB</span> </li> <li class="tng-asset-download-item"> <a class="tng-link is-neutral is-md" href="#" download> <span class="tng-overflow-ellipsis"> Download price list.jpg </span> <i class="tng-icon icon-download" aria-hidden="true"></i> </a> <span class="tng-asset-download-meta">12 MB</span> </li></ul>Everything clickable is in that one link, so a row is one tab stop.
The row is a native <a>, so the browser handles the outcome — keyboard activation, Open in New Tab and Save Link As all come for free. Don’t intercept the click with bespoke JavaScript download logic, and don’t script the new tab open with window.open; target="_blank" already does it and keeps the browser’s own controls working.
Elements
Section titled “Elements”Item without the list
Section titled “Item without the list”.tng-asset-download-item styles itself, so a row renders correctly outside .tng-asset-download. This exists for platforms that emit one asset per component instance and can’t wrap them in a shared list — it is not the supported shape, and Design and Accessibility document only the list.
What you give up is what the list owns: the dividers above and below each row, and the role="list" reset. Stacking these boxes doesn’t reassemble a list either — each container draws its own leading and trailing edge, so consecutive instances meet in a doubled seam you have to collapse in your own CSS. Use the <ul> whenever you can wrap the rows.
<div class="tng-asset-download-item"> <a class="tng-link is-neutral is-md" href="#" target="_blank" rel="noopener noreferrer" > <span class="tng-overflow-ellipsis">Download brochure.pdf</span> <span class="sr-only">(opens in a new tab)</span> <i class="tng-icon icon-external-link" aria-hidden="true"></i> </a> <span class="tng-asset-download-meta">100 MB</span></div>Description
Section titled “Description”The Static Asset Download component renders a list-based item allowing users to download a file or open a PDF in a new tab.
The file type decides the behaviour, and the component derives it from the asset rather than from a prop: a PDF opens in a new tab and gains the trailing external-link glyph, while every other format downloads directly and carries no glyph. opensInNewWindowLabel is the announcement that pairs with that new tab.
Component
Section titled “Component”Properties
Section titled “Properties”StaticAssetDownloadProperties extends the standard HTML attributes that can be applied to a <div>.
| Prop | Type | Description | Required |
|---|---|---|---|
themeStyleIds |
ThemeStyleId[] |
Defines the component’s colour scheme (e.g. ['light'] or ['dark']). Defaults to light |
|
title |
string |
The display name of the asset | |
titleFromAsset |
boolean |
Whether the title is automatically inherited from the DAM asset instead of manually entered | ✅ |
assetMetadata |
AssetMetadata |
Metadata object containing details like file type (fileFormat) and file size (fileSize) |
|
fileReference |
string |
The path or URL linking directly to the asset in AEM | |
opensInNewWindowLabel |
string |
Accessible label read by screen readers when a PDF file opens in a new window | ✅ |
id |
string |
Unique HTML id for the component container | |
displayFileFormat |
boolean |
When true, visually displays the format type of the file next to the title |
✅ |
displayFileSize |
boolean |
When true, visually displays the file size below the title |
✅ |
hasDividers |
boolean |
When true, horizontal dividers are added above and below the asset download row |
|
className |
ClassValue |
Additional CSS classes to apply to the container |
Example
Section titled “Example”import { StaticAssetDownload } from '@tmedxp/aem-react-components';
const StaticAssetDownloadExample = (model) => { return ( <StaticAssetDownload id={model.id} themeStyleIds={model.themeStyleIds} title={model.title} titleFromAsset={model.titleFromAsset} assetMetadata={model.assetMetadata} fileReference={model.fileReference} displayFileFormat={model.displayFileFormat} displayFileSize={model.displayFileSize} opensInNewWindowLabel={i18n( 'toyota/i18n/accessibility/labels:a11yOpensInNewWindow', )} /> );};
export { StaticAssetDownloadExample };An asset download is a list of asset links — each row a single native <a> naming the file it points at — so it has no dedicated WAI-ARIA interaction pattern; it leans on native link and list semantics, and meets WCAG 2.1 AA. Accessibility hinges on two things: the link taking its accessible name from its visible text, and that name saying which of the two things the row does. One row opens the asset in a new tab; the next saves it. Same markup, same single tab stop, different outcome — and the trailing glyph that separates them for a sighted user is decorative, so a screen-reader user has only the name to go on.
For designers
Section titled “For designers”- The label, file size, and the trailing glyph — including their hover and focus states — must maintain accessible contrast on every supported surface. The file size uses a subtler foreground than the label, so check it specifically rather than assuming the label’s pass carries over. Source: WCAG 1.4.3 Contrast (Minimum).
- Never rely on colour to say what a row does — the visible label already names the action in text; keep it that way. The label is underlined, so its link affordance doesn’t rest on colour either. The two glyphs differ in shape, not colour (they take the link’s colour, which is the same on both rows), and the file extension in the label says the same thing in text — so the preview-versus-save distinction never rests on colour alone. Draw the two shapes distinctly enough that the difference survives a small glyph. Source: WCAG 1.4.1 Use of Color.
- Focus styles must stay visible, meet contrast requirements on every supported surface, and be clearly distinguishable from hover. The focus ring wraps the filename and its trailing glyph together, since both are inside the link — leave room around the row for it to draw. Source: WCAG 2.4.7 Focus Visible.
- One row is one target. The link — the filename plus its trailing glyph — is a single hit area, which clears the minimum target size comfortably at every size; there is no second control to keep clear of. Source: WCAG 2.5.8 Target Size (Minimum).
- Use semantic colour tokens (e.g.
foreground/neutral/default) rather than fixed values, so the component adapts correctly across themes and surfaces.
For developers
Section titled “For developers”Render the assets as a native list — a <ul>, or an <ol> when the order is meaningful — of rows, each row a single <a>. The browser’s native link and download handling carries keyboard activation, Open in New Tab, and Save Link As for free, so don’t intercept clicks with bespoke JavaScript download logic that would break them. Keep the label text self-describing — the filename with its extension — rather than reaching for an aria-label.
The file type picks the element, the element has to match what actually happens, and the glyph has to match both:
- Opens in a new tab (a PDF the browser renders) —
<a target="_blank" rel="noopener noreferrer">closing withicon-external-link. The new tab is a context change, so the link must announce it. Append a.sr-onlyspan to the label —<span class="sr-only">(opens in a new tab)</span>— rather than overwriting the whole name with anaria-label. - Saves the file (every other format) —
<a download>closing withicon-download. The file saves and the tab doesn’t move, so there is nothing to announce beyond the filename, and nothing to append.
Never ship the announcement without the behaviour, or the behaviour without the announcement. A row that says “opens in a new tab” and then downloads is worse than one that says nothing. The glyph is under the same rule for sighted users — it is the only thing on screen that distinguishes the two rows, so a mismatched shape is a lie told in pictures.
The glyph is decorative — mark it aria-hidden="true". It should never get an <a> of its own: a glyph that leads where the label leads adds a tab stop and a second announcement of a destination the user has already been offered, and nesting one link inside another is invalid HTML besides. One row, one link, one tab stop — and the row order is the tab order, whichever behaviour each row carries.
Where the glyph sits in the DOM is a visual-design decision, not an accessibility one, since it is neither focusable nor named: it is the Link’s own trailing icon, which is what makes it take the link’s colour and states. Don’t wrap the row — link and size — in an outer <a> to “make it all clickable”; that would pull the file size into the accessible name.
Don’t wrap the <ul> / <ol> in a landmark unless the surrounding page genuinely needs one; the list is content, not navigation. The per-element roles, names, and states are in the Labelling elements section below.
Labelling elements
Section titled “Labelling elements”Give every element the role, name, and state assistive technology needs.
Row link
A native <a> that takes its accessible name from its visible text — the filename with its extension, so a screen reader announces “Download brochure.pdf”. Wrap that text in a <span>; the trailing glyph inside the link is hidden and adds nothing to the name. The file size sits outside the link and isn’t part of it either, so put the size in the label only if it genuinely needs announcing. Only add an aria-label when a surface needs a different announcement, and never leave the name to a glyph alone.
On a row that opens a new tab, the name carries one thing more: the new tab. Append a .sr-only span rather than overwriting the whole name with an aria-label.
List
The wrapping <ul> (or <ol>) carries role="list" explicitly, so the count still announces when list-style is removed — Safari with VoiceOver drops the implicit list role otherwise. It needs no aria-label: the rows are self-describing, so a redundant list label only adds noise.
Trailing glyph
aria-hidden="true" on both shapes: it is a visual cue, not a control. It is the sighted user’s read on what the row does — external-link for a new tab, download for a save — and the visible label already names the action in text.
Hiding it does not mean the cue is dropped for everyone else. On a new-tab row the warning belongs to the link’s name instead, where assistive tech will actually reach it; the .sr-only text is a sibling of the glyph, not a label for it. Never mark the glyph aria-hidden="false" or give it a title to compensate; that announces a decoration rather than the link. And never let the glyph be the only place the behaviour is stated — a hidden shape says nothing to a screen reader.
Source: WCAG 4.1.2 Name, Role, Value.