# 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.