Source: https://monarchui.dev/components/description-list/

Components · Data display

# DescriptionList

Key/value facts on detail pages, with copyable values, empty placeholders and clamped long values.

@rookcom/monarch-react

Component

## Record facts

## Usage examples

### Copyable values and empty placeholders

### Inline layout with a clamped value

### Responsive columns

## Purpose

Key/value facts on a detail page (owner, stage, created, …), as a semantic `<dl>`. Items can offer a copy button, show a placeholder for empty values, and clamp long values behind "Show more".

### Use when

- Showing read-only fields of one record.
- Ids, keys and URLs people copy: use `copyable`.
- Values that may be missing: the placeholder replaces hand-rolled em dashes.

### Avoid when

- Comparing many records: use a table.
- Editable fields: use a form with Field, or InlineEditText per value.

## Design principles

- Semantic markup: each item is a `<dt>`/`<dd>` pair.
- Values wrap anywhere so long ids and URLs never overflow.
- An empty value is visibly empty (a muted dash) and audibly named ("Not set"), never a blank cell.
- Truncation never hides data: the full value is one "Show more" away, not only in a tooltip.

## API reference

```tsx
import { DescriptionItem, DescriptionList } from '@rookcom/monarch-react';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `DescriptionItem` | component | server-safe | `.mn-dl-min-column` |
| `DescriptionList` | component | server-safe | `.mn-dl-min-column` |

DescriptionList renders a `<dl>`; DescriptionItem a `<div>` with `<dt>` and `<dd>`. Both forward their ref.

Server-safe: the list and items have no state. The copy button and the clamp toggle are client components rendered only when used.

`--mn-dl-min-column` sets the minimum column width of `columns="auto"` (default 12rem).

Generated from the TypeScript declarations of `packages/react/src/components/data-display/description-list`.

## Properties

### `DescriptionItem`

| Prop | Type | Description |
| --- | --- | --- |
| `term` required | `ReactNode` |  |
| `children` | `ReactNode` | The value. `null`, `undefined`, `false` and `''` render the `placeholder`. |
| `className` | `string` |  |
| `collapseLabel` | `string` | Label of the collapse button. Default "Show less". |
| `copyable` | `string \| boolean` | Adds an icon CopyButton after the value. `true` copies the value when it is a string or number; pass a string to copy something else (the full id behind a shortened one). Not shown for an empty value. |
| `copyLabel` | `string` | Accessible name of the copy button. Default "Copy" followed by the term when it is text. |
| `emptyLabel` | `string` | Screen-reader text for the default placeholder. Default "Not set". |
| `expandLabel` | `string` | Label of the expand button. Default "Show more". |
| `placeholder` | `ReactNode` | Shown for an empty value. Default an em dash, read as `emptyLabel`. |
| `truncate` | `number \| boolean` | Clamp the value to this many lines (`true` is 1) with a "Show more" button that expands it. The button appears only when the text overflows. |
| `wide` | `boolean` | Span all columns. |

### `DescriptionList`

Key/value facts on detail pages (owner, stage, created, …).

| Prop | Type | Description |
| --- | --- | --- |
| `children` | `ReactNode` |  |
| `className` | `string` |  |
| `columns` | `3 \| 1 \| "auto" \| 4 \| 2` | Grid columns. `auto` fits as many columns of at least `--mn-dl-min-column` (default 12rem) as the width allows. Every value becomes one column below 640px. Default 2. |
| `id` | `string` |  |
| `layout` | `"inline" \| "stacked"` | `stacked` (default, vertical) puts the term above the value; `inline` (horizontal) puts them side by side, and stacks again below 420px. |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `columns` | `'1'``'2'``'3'``'4'``'auto'` | Grid columns. Default `2`. `4` drops to two columns below 1024px; `auto` fits columns of at least `--mn-dl-min-column`. Exposed as `data-columns`. |
| `layout` | `'stacked'``'inline'` | `stacked` (default, vertical) puts the term above the value; `inline` (horizontal) side by side. Exposed as `data-layout`. |
| `DescriptionItem wide` | `'true'``'false'` | Spans all columns (`data-wide`). |
| `DescriptionItem copyable` | `'false'``'true'``'string'` | `true` copies a text value; a string copies that text (the full key behind a masked one). |
| `DescriptionItem truncate` | `'false'``'true (1 line)'``'number of lines'` | Clamps the value and adds "Show more" when it overflows. |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Empty | `data-empty on the item` | `null`, `undefined`, `false` or `""` render the placeholder (default a muted em dash read as "Not set"). `0` is a value. |
| Clamped / expanded | `data-expanded on .mn-dl__clamp` | The toggle shows only when the text overflows the clamp; `aria-expanded` follows. |
| Copied | – | The copy button shows a check and announces "Copied to clipboard" (CopyButton). |

## Interaction behaviour

- The copy button copies the value and confirms in place.
- "Show more" expands the clamped value; "Show less" clamps it again.
- The overflow check runs after mount and on resize, so a value that fits never shows a toggle.

## Keyboard support

| Keys | Action |
| --- | --- |
| Tab | Moves to each copy button and "Show more" toggle in reading order. |
| Enter / Space | Copies the value, or expands and collapses it. |

A list without copyable or truncated items has nothing to focus.

## Accessibility

Role

none (native dl/dt/dd semantics)

Accessible name

–

- Terms render as `<dt>` and values as `<dd>`, so screen readers pair them.
- The copy button is named "Copy {term}" when the term is text; pass `copyLabel` otherwise.
- The expand toggle is a button with `aria-expanded` and `aria-controls` pointing at the value.
- The default placeholder hides the dash from assistive technology and reads `emptyLabel` instead.

## Responsive behaviour

- At 640px and below every column count collapses to one column.
- `columns={4}` shows two columns between 641px and 1023px.
- In `inline` layout terms take a fixed 9rem column, and stack above the value below 420px.

## Theme support

- Term, value, placeholder and link-coloured toggle use semantic text tokens.
- The toggle focus ring uses `--mn-color-focus-ring`.

## Do and don't

### Do

- Use `wide` for long values such as notes or addresses.
- Pass missing values straight through; the placeholder handles them.
- Make ids, keys and URLs `copyable`.

### Don't

- Do not put form controls in a description list.
- Do not hide truncated values behind a `title` attribute only; use `truncate`.

## Related components

- [RecordHeader](https://monarchui.dev/components/record-header/): Renders its key facts with a DescriptionList.
- [CopyButton](https://monarchui.dev/components/copy-button/): The copy affordance on `copyable` items.
- [Card](https://monarchui.dev/components/card/): A surface to group the list.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `react` |
| Monarch components | [CopyButton](https://monarchui.dev/components/copy-button/) |

## Testing coverage

- Renders terms as `<dt>` and values as `<dd>`.
- Exposes columns and layout and forwards refs.
- Empty values show the placeholder read as "Not set"; `0` is a value.
- Copies values with the keyboard and the pointer; no copy button for empty values.
- Clamps long values with an `aria-expanded` toggle shown only on overflow.
- Renders on the server.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery/description-list; Cross-browser axe: /components/description-list |

Tests: `packages/react/src/components/data-display/description-list`

## All example code

### Record facts

```tsx
import { DescriptionItem, DescriptionList } from '@rookcom/monarch-react';

<DescriptionList columns={2} style={{ width: '100%' }}>
  <DescriptionItem term="Owner">Ada Lovelace</DescriptionItem>
  <DescriptionItem term="Stage">Proposal</DescriptionItem>
  <DescriptionItem term="Created">3 March</DescriptionItem>
  <DescriptionItem term="Source">Inbound</DescriptionItem>
  <DescriptionItem term="Notes" wide>
    Follow up after the product review.
  </DescriptionItem>
</DescriptionList>
```

### Copyable values and empty placeholders

```tsx
import { DescriptionItem, DescriptionList } from '@rookcom/monarch-react';

<DescriptionList columns={2} style={{ width: '100%' }}>
  <DescriptionItem term="Workspace ID" copyable>
    ws_8f2a91c4
  </DescriptionItem>
  <DescriptionItem term="Webhook URL" copyable>
    https://hooks.example.com/w/8f2a91c4
  </DescriptionItem>
  <DescriptionItem term="Phone">{null}</DescriptionItem>
  <DescriptionItem term="Tax ID" placeholder="Not provided">
    {''}
  </DescriptionItem>
</DescriptionList>
```

### Inline layout with a clamped value

```tsx
import { DescriptionItem, DescriptionList } from '@rookcom/monarch-react';

<DescriptionList
  layout="inline"
  columns={1}
  style={{ width: '100%', maxWidth: '32rem' }}
>
  <DescriptionItem term="Page title">
    Pricing plans for teams of every size
  </DescriptionItem>
  <DescriptionItem term="Meta description" truncate={2}>
    Compare plans side by side, see what each includes, and start a free trial. Every
    plan includes unlimited projects, guest access and priority support during business
    hours, with annual billing available at a discount.
  </DescriptionItem>
  <DescriptionItem term="Canonical">{null}</DescriptionItem>
</DescriptionList>
```

### Responsive columns

```tsx
import { DescriptionItem, DescriptionList } from '@rookcom/monarch-react';

<DescriptionList columns="auto" style={{ width: '100%' }}>
  <DescriptionItem term="Plan">Team</DescriptionItem>
  <DescriptionItem term="Seats">12 of 15</DescriptionItem>
  <DescriptionItem term="Renews">1 June</DescriptionItem>
  <DescriptionItem term="Billing">Annual</DescriptionItem>
</DescriptionList>
```
