List
A list brings names, icons, figures and actions onto the same grid. These examples use one-square rows, aligned icon cells and shared text styles.
Examples
Section titled “Examples”Names, reference codes and tabular amounts share one baseline. The currency column stays aligned as values change.
<ds-list class="showcase">
<ds-row ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Bookbinding</ds-text><ds-text literal class="meta code secondary" tone="muted">RC-1042</ds-text><ds-text literal class="number" >48.00</ds-text></ds-row>
<ds-row ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Studio paper</ds-text><ds-text literal class="meta code secondary" tone="muted">RC-1043</ds-text><ds-text literal class="number" >126.50</ds-text></ds-row>
<ds-row ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Courier</ds-text><ds-text literal class="meta code secondary" tone="muted">RC-1044</ds-text><ds-text literal class="number" >9.80</ds-text></ds-row>
<ds-row ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Print proofs</ds-text><ds-text literal class="meta code secondary" tone="muted">RC-1045</ds-text><ds-text literal class="number" >72.00</ds-text></ds-row>
<ds-row ><ds-text literal class="name" strong>Total</ds-text><ds-text literal class="number" strong>256.30</ds-text></ds-row>
</ds-list>
<style>
.showcase { width: 100%; --cell: calc(20px * var(--sf, 1)); }
.showcase ds-row { gap: 0; }
.showcase .mark { display: inline-flex; align-items: flex-end; height: var(--ds-control-height); width: var(--cell); flex: 0 0 var(--cell); }
.showcase .name { flex: 1; min-width: 0; }
.showcase .meta { width: calc(5 * var(--cell)); flex: 0 0 calc(5 * var(--cell)); }
.showcase .number { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); text-align: right; font-variant-numeric: tabular-nums; --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .code { --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .time { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .group { margin-top: var(--cell); }
@media (max-width: 420px) { .showcase .secondary { display: none; } }
</style> A check, a title and a small reading time sit on the same row. The current destination is highlighted; muted text marks what is finished.
<ds-list class="showcase">
<ds-row interactive nav ><span class="mark"><ds-icon size="large" type="check" aria-hidden="true"></ds-icon></span><ds-text literal class="name" tone="muted">The shape of a city</ds-text><ds-text literal class="meta" size="small" tone="muted">12 min</ds-text></ds-row>
<ds-row interactive nav current><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Walking after rain</ds-text><ds-text literal class="meta" size="small" tone="muted">8 min</ds-text></ds-row>
<ds-row interactive nav ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Notes from the coast</ds-text><ds-text literal class="meta" size="small" tone="muted">16 min</ds-text></ds-row>
<ds-row interactive nav ><span class="mark"><ds-icon size="large" type="star" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >A small observatory</ds-text><ds-text literal class="meta" size="small" tone="muted">6 min</ds-text></ds-row>
</ds-list>
<style>
.showcase { width: 100%; --cell: calc(20px * var(--sf, 1)); }
.showcase ds-row { gap: 0; }
.showcase .mark { display: inline-flex; align-items: flex-end; height: var(--ds-control-height); width: var(--cell); flex: 0 0 var(--cell); }
.showcase .name { flex: 1; min-width: 0; }
.showcase .meta { width: calc(5 * var(--cell)); flex: 0 0 calc(5 * var(--cell)); }
.showcase .number { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); text-align: right; font-variant-numeric: tabular-nums; --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .code { --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .time { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .group { margin-top: var(--cell); }
@media (max-width: 420px) { .showcase .secondary { display: none; } }
</style> Different file icons occupy the same square. Filenames use a monospace face; the names, formats and sizes keep their columns.
<ds-list class="showcase">
<ds-row ><span class="mark"><ds-icon size="large" type="folder" aria-hidden="true"></ds-icon></span><ds-text literal class="name code" >Reference</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Folder</ds-text><ds-text literal class="number" >6 files</ds-text></ds-row>
<ds-row ><span class="mark"><ds-icon size="large" type="pdf" aria-hidden="true"></ds-icon></span><ds-text literal class="name code" >field-guide.pdf</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Document</ds-text><ds-text literal class="number" >2.4 MB</ds-text></ds-row>
<ds-row ><span class="mark"><ds-icon size="large" type="image" aria-hidden="true"></ds-icon></span><ds-text literal class="name code" >north-window.jpg</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Image</ds-text><ds-text literal class="number" >840 KB</ds-text></ds-row>
<ds-row ><span class="mark"><ds-icon size="large" type="music" aria-hidden="true"></ds-icon></span><ds-text literal class="name code" >room-tone.wav</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Audio</ds-text><ds-text literal class="number" >18 MB</ds-text></ds-row>
<ds-row ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name code" >notes.txt</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Text</ds-text><ds-text literal class="number" >4 KB</ds-text></ds-row>
</ds-list>
<style>
.showcase { width: 100%; --cell: calc(20px * var(--sf, 1)); }
.showcase ds-row { gap: 0; }
.showcase .mark { display: inline-flex; align-items: flex-end; height: var(--ds-control-height); width: var(--cell); flex: 0 0 var(--cell); }
.showcase .name { flex: 1; min-width: 0; }
.showcase .meta { width: calc(5 * var(--cell)); flex: 0 0 calc(5 * var(--cell)); }
.showcase .number { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); text-align: right; font-variant-numeric: tabular-nums; --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .code { --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .time { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .group { margin-top: var(--cell); }
@media (max-width: 420px) { .showcase .secondary { display: none; } }
</style> Times use a fixed-width face, session names use regular text, and room labels use the small size. Every session is one square high.
<ds-list class="showcase">
<ds-row ><ds-text literal class="time" >13:00</ds-text><span class="mark"><ds-icon size="large" type="calendar" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Doors open</ds-text><ds-text literal class="meta" tone="muted" size="small">Foyer</ds-text></ds-row>
<ds-row ><ds-text literal class="time" >13:30</ds-text><span class="mark"><ds-icon size="large" type="calendar" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Drawing with light</ds-text><ds-text literal class="meta" tone="muted" size="small">Room 2</ds-text></ds-row>
<ds-row ><ds-text literal class="time" >14:15</ds-text><span class="mark"><ds-icon size="large" type="calendar" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >A short interval</ds-text><ds-text literal class="meta" tone="muted" size="small">Garden</ds-text></ds-row>
<ds-row ><ds-text literal class="time" >14:30</ds-text><span class="mark"><ds-icon size="large" type="calendar" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Listening to spaces</ds-text><ds-text literal class="meta" tone="muted" size="small">Room 1</ds-text></ds-row>
<ds-row ><ds-text literal class="time" >15:30</ds-text><span class="mark"><ds-icon size="large" type="calendar" aria-hidden="true"></ds-icon></span><ds-text literal class="name" >Questions and tea</ds-text><ds-text literal class="meta" tone="muted" size="small">Foyer</ds-text></ds-row>
</ds-list>
<style>
.showcase { width: 100%; --cell: calc(20px * var(--sf, 1)); }
.showcase ds-row { gap: 0; }
.showcase .mark { display: inline-flex; align-items: flex-end; height: var(--ds-control-height); width: var(--cell); flex: 0 0 var(--cell); }
.showcase .name { flex: 1; min-width: 0; }
.showcase .meta { width: calc(5 * var(--cell)); flex: 0 0 calc(5 * var(--cell)); }
.showcase .number { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); text-align: right; font-variant-numeric: tabular-nums; --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .code { --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .time { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .group { margin-top: var(--cell); }
@media (max-width: 420px) { .showcase .secondary { display: none; } }
</style> Initials, names, roles and availability align without pictures. The avatar and label share the lower sixteen of each row.
<ds-list class="showcase">
<ds-row ><span class="mark"><ds-avatar label="Mina Ito" initial="M"></ds-avatar></span><ds-text literal class="name" >Mina Ito</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Editor</ds-text><ds-text literal class="meta" size="small">Available</ds-text></ds-row>
<ds-row ><span class="mark"><ds-avatar label="Alex Reed" initial="A"></ds-avatar></span><ds-text literal class="name" >Alex Reed</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Photographer</ds-text><ds-text literal class="meta" size="small">Away</ds-text></ds-row>
<ds-row ><span class="mark"><ds-avatar label="Noor Patel" initial="N"></ds-avatar></span><ds-text literal class="name" >Noor Patel</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Researcher</ds-text><ds-text literal class="meta" size="small">Available</ds-text></ds-row>
<ds-row ><span class="mark"><ds-avatar label="Sam Rivera" initial="S"></ds-avatar></span><ds-text literal class="name" >Sam Rivera</ds-text><ds-text literal class="meta secondary" tone="muted" size="small">Producer</ds-text><ds-text literal class="meta" size="small">In a meeting</ds-text></ds-row>
</ds-list>
<style>
.showcase { width: 100%; --cell: calc(20px * var(--sf, 1)); }
.showcase ds-row { gap: 0; }
.showcase .mark { display: inline-flex; align-items: flex-end; height: var(--ds-control-height); width: var(--cell); flex: 0 0 var(--cell); }
.showcase .name { flex: 1; min-width: 0; }
.showcase .meta { width: calc(5 * var(--cell)); flex: 0 0 calc(5 * var(--cell)); }
.showcase .number { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); text-align: right; font-variant-numeric: tabular-nums; --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .code { --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .time { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .group { margin-top: var(--cell); }
@media (max-width: 420px) { .showcase .secondary { display: none; } }
</style> Each entry uses two aligned rows: a stronger title above, with a quiet description and reference below. The icon column stays open on the second line.
<ds-list class="showcase">
<div> <ds-row ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" strong>Field recordings</ds-text><ds-text literal class="meta code" tone="muted">FR-028</ds-text></ds-row> <ds-row ><span class="mark"></span><ds-text literal class="name" tone="muted" size="small">Coastal paths, early morning</ds-text></ds-row></div>
<div> <ds-row ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" strong>Material studies</ds-text><ds-text literal class="meta code" tone="muted">MS-013</ds-text></ds-row> <ds-row ><span class="mark"></span><ds-text literal class="name" tone="muted" size="small">Paper, cloth and translucent surfaces</ds-text></ds-row></div>
<div> <ds-row ><span class="mark"><ds-icon size="large" type="page" aria-hidden="true"></ds-icon></span><ds-text literal class="name" strong>Exhibition notes</ds-text><ds-text literal class="meta code" tone="muted">EN-006</ds-text></ds-row> <ds-row ><span class="mark"></span><ds-text literal class="name" tone="muted" size="small">Measurements and installation references</ds-text></ds-row></div>
</ds-list>
<style>
.showcase { width: 100%; --cell: calc(20px * var(--sf, 1)); }
.showcase ds-row { gap: 0; }
.showcase .mark { display: inline-flex; align-items: flex-end; height: var(--ds-control-height); width: var(--cell); flex: 0 0 var(--cell); }
.showcase .name { flex: 1; min-width: 0; }
.showcase .meta { width: calc(5 * var(--cell)); flex: 0 0 calc(5 * var(--cell)); }
.showcase .number { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); text-align: right; font-variant-numeric: tabular-nums; --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .code { --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .time { width: calc(4 * var(--cell)); flex: 0 0 calc(4 * var(--cell)); --ds-typeface-regular: var(--ds-typeface-mono); }
.showcase .group { margin-top: var(--cell); }
@media (max-width: 420px) { .showcase .secondary { display: none; } }
</style> Compose rows
Section titled “Compose rows”Put ds-row elements directly in the list. ds-list supplies the containing layout; each row supplies its alignment and content.
Rows of records
Section titled “Rows of records”A heading names each group; a picture on its square, the name, a tag and the amount at the end, no lines between the rows. Narrow the window to see a long name fade.
<style>
.records { display: grid; gap: var(--ds-unit); width: 100%; max-width: calc(28 * var(--ds-unit)); --ds-row-padding: 0px; }
</style>
<div class="records">
<ds-list heading="Yesterday">
<ds-row href="#coop"><ds-avatar shape="square" icon="cart" color="var(--ds-apple-green)"></ds-avatar><ds-text class="ds-row__name" literal>Co-op fresh market, Hakodate main street</ds-text><ds-tag>Cash</ds-tag><ds-text class="ds-row__value" literal>206.49 kr</ds-text></ds-row>
<ds-row href="#seven"><ds-avatar shape="square" icon="cart" color="var(--ds-orange)"></ds-avatar><ds-text class="ds-row__name" literal>Seven-Eleven</ds-text><ds-tag>Cash</ds-tag><ds-text class="ds-row__value" literal>12.52 kr</ds-text></ds-row>
</ds-list>
<ds-list heading="Monday">
<ds-row href="#juice"><ds-avatar shape="square" icon="cart" color="var(--ds-apple-green)"></ds-avatar><ds-text class="ds-row__name" literal>Apple juice</ds-text><ds-tag>Cash</ds-tag><ds-text class="ds-row__value" literal>5.89 kr</ds-text></ds-row>
<ds-row href="#coffee"><ds-avatar shape="square" icon="coffee" color="var(--ds-yellow)"></ds-avatar><ds-text class="ds-row__name" literal>Coffee</ds-text><ds-tag>Cash</ds-tag><ds-text class="ds-row__value" literal>5.05 kr</ds-text></ds-row>
<ds-row href="#laundry"><ds-avatar shape="square" icon="plus" color="var(--ds-pink)"></ds-avatar><ds-text class="ds-row__name" literal>Laundromat, Hakodate</ds-text><ds-tag style="--ds-tag-accent: var(--ds-sharp-blue)">JP Bank</ds-tag><ds-text class="ds-row__value" literal>46.29 kr</ds-text></ds-row>
<ds-row href="#sushi"><ds-avatar shape="square" icon="star" color="var(--ds-zenith-blue)"></ds-avatar><ds-text class="ds-row__name" literal>Hama-Sushi, Hakodate</ds-text><ds-tag>Cash</ds-tag><ds-text class="ds-row__value" literal>57.40 kr</ds-text></ds-row>
</ds-list>
</div> A list of records (payments under their day, events under their month) is the same list with heading, the group’s name drawn on the square above its rows in the muted ink, and rows with href whose parts are classes: a 16px picture before the name (an Avatar tile, shape="square" with icon and color, or a large Icon) on the first sixteen of its square, the words in ds-row__name on the next square, a Tag after them, and the figure or date in ds-row__value at the row’s end. The name hugs its words and gives way first: cut, it fades over its last square (the row measures it and marks it data-cut="end"). The rows stack edge to edge with no lines between them; the pointer and a press fill the row’s layer, two pixels around what it holds. Give the list --ds-row-padding: 0px where its pictures and values stand on the column’s edges.
The heading names the list (aria-label), so the drawn words are hidden from assistive technology; a page that writes its own aria-label keeps it. Each group is its own list, one square apart on a page.
<ds-list heading="Monday" style="--ds-row-padding: 0px"> <ds-row href="/laundromat"> <ds-avatar shape="square" icon="plus" color="var(--ds-pink)"></ds-avatar> <ds-text class="ds-row__name" literal>Laundromat, Hakodate</ds-text> <ds-tag>JP Bank</ds-tag> <ds-text class="ds-row__value" literal>46.29 kr</ds-text> </ds-row></ds-list>The element is a list: it takes role="list", and every element directly inside it role="listitem", including rows added later. A row taken out of the list loses the role the list gave it. Roles the page writes are left alone: a list with a role of its own (such as listbox, or none for a list used only for layout) gives its children no role, and a child with a role keeps it. Screen readers then announce the list and its number of items, as for <ul> and <li>.
The component has a default slot, the columns attribute, which lays the items out in that many equal columns, and heading, the group’s name on the square above the rows (its part is heading; --ds-list-heading-color is its ink). There is no ds-list-item custom element, sorting API or selection state built into it.