# Summary List
Display labelled data for users to review.
Section: components
Docs: https://nebula.kaluza.com/components/summary-list
---
## When to use
- On a review or confirmation page to show what a user has entered before submitting
- To display the key attributes of a single entity, for example an account's name, address, and tariff
- Anywhere a set of labelled values needs to be presented in a structured, readable format
## When not to use
- **To compare data across multiple entities** - use [Data Table](/components/data-table) instead. Summary List is for a single entity's attributes, not a grid of items.
- **For a plain list of items without labels** - use [List](/components/list) instead.
- **For a small number of inline key-value pairs within body copy** - use plain text instead to avoid adding structural overhead to simple content.
## Anatomy
1. **Label**
2. **Value**
## Basic usage
```tsx
David Attenborough
94
```
## Variants and features
### Rich values
Values can contain any React content, including formatted numbers, [Badges](/components/badge), [Text Links](/components/text-link), or other inline components.
```tsx
A-001234
Active
1 Example Street, London, EC1A 1BB
```
## Content
### Labels
Labels identify what the value represents. Keep them short and noun-based, for example "Name", "Date of birth", "Account number". Avoid full sentences or questions as labels.
### Values
Values should be unambiguous. For empty or inapplicable values, use a short descriptive phrase such as "None" or "Not applicable" rather than leaving the space blank. This makes it clear the absence of a value is intentional.
### Action links
When a value row includes an action link such as "Change" on a review page, include context about what is being changed in the link text. The simplest way to do this is to add a `` span with the label name, for example:
```tsx
David Attenborough
Change name
8 May 1926
Change date of birth
```
This gives screen reader users "Change name" rather than hearing the word "Change" repeated for every row without context.
## Rules and guidance
### Usage
- **SummaryList** SHOULD be used to display attributes of a single entity, not to compare multiple entities. Rationale: SummaryList renders a definition list, a semantic structure for one subject and its properties. Comparing multiple items across columns requires a different structure. Use DataTable instead. [id: summarylist.single-entity-only; testability: manual]
- **SummaryList** MUST NOT be used in place of DataTable for data that compares multiple items of the same type. Rationale: SummaryList lacks column headers and tabular semantics. Using it for comparative data makes it harder to scan and removes the accessibility benefits of a proper table structure. [id: summarylist.no-table-replacement; testability: manual]
### Content
- **SummaryList** WILL render as a dl element, with each SummaryItem label as a dt and each value as a dd. Screen readers announce this structure as a description list. [id: summarylist.will-dl-semantics; testability: auto]
- **SummaryItem** MUST always include a label. Rationale: The label prop renders as a dt element and is required by the TypeScript type. A SummaryItem without a label produces an orphaned dd with no associated term, which is invalid HTML semantics. [id: summarylist.label-required; testability: auto]
- **SummaryItem label** SHOULD use a concise noun or noun phrase, not a question or full sentence. Rationale: Labels are scanned quickly before reading the corresponding value. Questions and full sentences slow this scanning pattern and add visual weight disproportionate to the role of a label. [id: summarylist.label-nouns; testability: manual]
- **SummaryList** SHOULD use labels in a consistent grammatical format throughout the list. Rationale: Mixing nouns, verbs, and questions within a single list disrupts the visual rhythm and makes the list harder to scan. Users rely on the consistent structure of labels to navigate efficiently. [id: summarylist.label-consistent-format; testability: manual]
- If the value contains a link that triggers an edit action: **SummaryItem action link** SHOULD include the label name as visually hidden text within the link so screen reader users hear "Change [label]" rather than repeated "Change" links with no context. Rationale: A row of identical "Change" links is ambiguous when navigated by keyboard or screen reader. Adding visually hidden context ("Change name", "Change address") removes the ambiguity without affecting sighted users. [id: summarylist.action-link-context; testability: manual]
- **SummaryItem value** SHOULD NOT be left visually blank when a value is absent or not applicable. Rationale: An empty value gives no indication of whether the data is missing, unavailable, or intentionally absent. Use a short descriptive phrase such as "None" or "Not applicable" to signal intentional absence clearly. [id: summarylist.no-empty-values; testability: manual]
## Accessibility
### In brief
Summary List is a native description list. A screen reader announces each label as a term and its value as the definition. It never takes focus.
### What Nebula provides
- Each label is a `dt` and each value a `dd` inside a `dl`, so the pairing is in the markup and not only in the layout.
### Accessible design
#### Write each label so it names its value without the items around it
A screen reader user can move from one term to the next, so "Delivery address" works and "Address 2" does not.
WCAG: [2.4.6 Headings and Labels](https://www.w3.org/WAI/WCAG22/Understanding/headings-and-labels.html)
#### Write every value as text
An icon or a colour alone does not reach a screen reader, so the value has to be in the text of the item.
WCAG: [1.4.1 Use of Color](https://www.w3.org/WAI/WCAG22/Understanding/use-of-color.html) [1.1.1 Non-text Content](https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html)
### Accessible development
#### Keep `SummaryItem` as the only child of a `SummaryList`
`SummaryList` renders a `dl`, which only allows terms and definitions. Other children break the list structure a screen reader announces.
WCAG: [1.3.1 Info and Relationships](https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html)
### Accessibility testing status
Reviewed on 9 October 2026 against v17.0.1.
| Test | Status | Tested with |
| --- | --- | --- |
| Default state | Tested | axe-core via the Storybook test runner (CI) |
| Advanced states | Not tested | — |
| Keyboard navigation | Manually tested | keyboard (reported by the owner) |
| Screen reader | Manually tested | VoiceOver with Chrome (reported by the owner) |
What each test covers:
- Default state: The component as it first appears, before anything is clicked or changed.
- Advanced states: Every other state and variant: error, open, selected, each size and style, and hovering.
- Keyboard navigation: Whether every function can be reached and used with the keyboard alone, with a visible focus ring.
- Screen reader: Whether a screen reader announces what is on screen correctly: the name, the role and any state.
What these statuses mean:
- Tested: Every check in this row passed in an automated run that repeats on every pull request.
- Manually tested: Every check in this row was run once, by a person or with a tool they started, and all of them passed. It is not re-run on every change.
- Partially tested: Some checks in this row were run once and passed; the rest are still to do.
- Issue found: A check in this row failed. The ticket is shown beside the status.
- Not tested: No check in this row has been run yet.
- Not applicable: This row does not apply to the component, for the reason given beside it.
The table records which checks were run on this component on its own. It is not a statement of WCAG conformance, and it does not cover how the component is used.
## Properties
### SummaryList
- `as` (type `ElementType`, optional). Renders the component as a different element or component, e.g. `as="section"`.
- `forwardedAs` (type `ElementType`, optional). Like `as`, but passed on to the component being wrapped, for when a styled wrapper should keep its own element and change the one beneath it.
### SummaryItem
- `label` (type `ReactNode`, required). Term shown in the item's label (`dt`), with the children shown as its value (`dd`).
- `as` (type `ElementType`, optional). Renders the component as a different element or component, e.g. `as="section"`.
- `forwardedAs` (type `ElementType`, optional). Like `as`, but passed on to the component being wrapped, for when a styled wrapper should keep its own element and change the one beneath it.