On this page
Styled list elements for ordered, unordered, and definition lists
- Overview
- Rules and guidance
- Properties
- Styles
- Accessibility
When to use
- When presenting multiple items that benefit from visual separation rather than running together as prose
- When items have an inherent order, priority, or sequence that matters: use an ordered list (Ol)
- When items are discrete and parallel but have no meaningful order: use an unordered list (Ul)
- When presenting term-and-definition pairs such as a glossary or a set of key facts: use a definition list (Dl with Dt and Dd)
When not to use
- For two or fewer items - these read more naturally as prose. Use Text (P) instead.
- For key-value data about an entity - use Summary List instead, which is built for structured data rows and provides better semantics for that pattern.
- For navigation links - use the appropriate navigation component rather than a list of Text Links.
Anatomy
Unordered and ordered lists:
- List container (Ul or Ol)
- List item (Li)
Definition lists:
- Definition list container (Dl)
- Term (Dt)
- Definition (Dd)
Basic usage
Edit live code
<Ol> <Li>An example of body text.</Li> <Li> An example with <Em>emphasis</Em> and <Strong>strong text</Strong>. </Li> </Ol>
Variants and features
Unordered list
Use Ul when the items are discrete but their order carries no meaning. Items are presented with a disc bullet marker.
Edit live code
<Ul> <Li>An example of body text.</Li> <Li> An example with <Em>emphasis</Em> and <Strong>strong text</Strong>. </Li> </Ul>
Ordered list
Use Ol when the sequence matters, for example a set of steps or a ranked priority list. Items are numbered automatically.
Edit live code
<Ol> <Li>Take a meter reading</Li> <Li>Enter it in your account</Li> <Li>Wait for your updated bill</Li> </Ol>
Definition list
Use Dl with Dt (term) and Dd (definition) for glossaries and term-definition pairs. Each term renders in semi-bold, and each definition follows immediately below it.
For structured data about an entity (such as an account summary), use Summary List instead.
Edit live code
<Dl> <Dt>MPAN</Dt> <Dd>A unique 13-digit number that identifies your electricity supply point.</Dd> <Dt>MPRN</Dt> <Dd>A unique number that identifies your gas supply point.</Dd> </Dl>
Inline formatting
Use Strong or Em from the Text component inside Li, Dt, or Dd elements to add emphasis where needed.
Edit live code
<Ul> <Li><Strong>Direct debit</Strong> (taken on the 1st of each month)</Li> <Li>Pay on receipt (pay when you receive your bill)</Li> </Ul>
Nested lists
Lists can be nested by placing a Ul or Ol inside a Li. Use nesting sparingly. More than two levels is usually a sign the content needs restructuring.
Edit live code
<Ul> <Li>Electricity <Ul> <Li>Standing charge</Li> <Li>Unit rate</Li> </Ul> </Li> <Li>Gas <Ul> <Li>Standing charge</Li> <Li>Unit rate</Li> </Ul> </Li> </Ul>
usage
- List content must use Nebula List components (Ul, Ol, Li, Dl, Dt, Dd) rather than raw HTML list elementsNebula list components apply responsive typography and spacing from the design token system.Copy rule ID for list.no-raw-elements
- Ul, Ol should contain at least two itemsA single-item list provides no benefit over a paragraph. Use P instead.Copy rule ID for list.minimum-items
- Ol should be used when the order of items is meaningful (steps, priority, ranking)Using Ol signals to users and assistive technology that sequence matters. Using Ul when order is meaningful removes this signal.Copy rule ID for list.ordered-when-sequence-matters
- Ul should be used when items are parallel but their order carries no meaningCopy rule ID for list.unordered-when-no-sequence
- Dl should be used for term-and-definition pairs such as glossaries or factual key-value contentCopy rule ID for list.dl-for-term-definition
- Dl should not be used for structured data rows about an entitySummaryList is purpose-built for that pattern and provides better styling and semantics.Copy rule ID for list.use-summary-list-for-entity-data
- Nested lists should not exceed two levels of nestingDeep nesting is visually complex and usually signals that content needs restructuring.Copy rule ID for list.nesting-depth
content
- Li, Dd should be grammatically parallel across items in the same listParallel structure makes lists easier to scan and understand.Copy rule ID for list.item-parallelism
- Li should not end with a full stop unless list items are complete sentencesCopy rule ID for list.no-terminal-punctuation
composition
- Li must be a direct child of Ul or OlPlacing Li outside a list container is invalid HTML and breaks screen reader list announcement.Copy rule ID for list.li-inside-ul-ol
- Dt, Dd must be direct children of DlCopy rule ID for list.dt-dd-inside-dl
- Dt must appear before the Dd element it describesCopy rule ID for list.dt-before-dd
Ul
Also accepts all props from HTMLAttributes.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
as | ElementType | — | No | Renders the component as a different element or component, e.g. `as="section"`. |
forwardedAs | ElementType | — | No | 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. |
Ol
Also accepts all props from HTMLAttributes, OlHTMLAttributes.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
as | ElementType | — | No | Renders the component as a different element or component, e.g. `as="section"`. |
forwardedAs | ElementType | — | No | 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. |
Li
Also accepts all props from HTMLAttributes, LiHTMLAttributes.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
as | ElementType | — | No | Renders the component as a different element or component, e.g. `as="section"`. |
forwardedAs | ElementType | — | No | 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. |
Dl
Also accepts all props from HTMLAttributes.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
as | ElementType | — | No | Renders the component as a different element or component, e.g. `as="section"`. |
forwardedAs | ElementType | — | No | 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. |
Dt
Also accepts all props from HTMLAttributes.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
as | ElementType | — | No | Renders the component as a different element or component, e.g. `as="section"`. |
forwardedAs | ElementType | — | No | 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. |
Dd
Also accepts all props from HTMLAttributes.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
as | ElementType | — | No | Renders the component as a different element or component, e.g. `as="section"`. |
forwardedAs | ElementType | — | No | 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. |
Styles
ul
list-style-type: disc;
margin-top: ${space[1]};
margin-bottom: ${space[1]};
margin-left: ${space[6]};
${mediaQueries.smallAndUp} {
margin-top: ${space[2]};
margin-bottom: ${space[2]};
}
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
ol
list-style-type: decimal;
margin-top: ${space[2]};
margin-bottom: ${space[1]};
margin-left: ${space[6]};
${mediaQueries.smallAndUp} {
margin-top: ${space[2]};
margin-bottom: ${space[2]};
}
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
li
font-family: ${fonts.body};
line-height: ${lineHeights.body};
font-weight: ${fontWeights.normal};
color: ${colors.body};
margin: ${space[2]} auto;
font-size: ${responsiveFontSizes.body[0]};
${mediaQueries.smallAndUp} {
font-size: ${responsiveFontSizes.body[1]};
}
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
dl
margin-top: ${space[1]};
margin-bottom: ${space[1]};
${mediaQueries.smallAndUp} {
margin-top: ${space[2]};
margin-bottom: ${space[2]};
}
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
dt
font-family: ${fonts.body};
line-height: ${lineHeights.body};
font-weight: ${fontWeights.semiBold};
color: ${colors.heading};
margin-top: ${space[2]};
margin-bottom: ${space[1]};
font-size: ${responsiveFontSizes.body[0]};
${mediaQueries.smallAndUp} {
font-size: ${responsiveFontSizes.body[1]};
margin-top: ${space[3]};
}
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
dd
font-family: ${fonts.body};
line-height: ${lineHeights.body};
font-weight: ${fontWeights.normal};
color: ${colors.body};
font-size: ${responsiveFontSizes.body[0]};
${mediaQueries.smallAndUp} {
font-size: ${responsiveFontSizes.body[1]};
}
dd + & {
margin-top: ${space[1]};
}
In brief
List is built from native ul, ol, li, dl, dt and dd elements. A screen reader can announce it as a list and say how many items it has, and reads a description list as terms with their details.
What Nebula provides
- Ul, Ol, Li, Dl, Dt and Dd render the native elements of the same name.
- Ul and Ol keep their markers (disc and decimal).
- A Dt can be followed by more than one Dd.
Accessible design
Use an ordered list only when the order matters
A numbered list tells the user the sequence carries meaning. Use an unordered list when it does not.
WCAG: 1.3.1 Info and Relationships
Use a description list for terms and their details
A glossary or a set of key and value pairs is read as a pair when it is a Dl. A run of bold labels and values is read as unrelated lines.
WCAG: 1.3.1 Info and Relationships
Accessible development
Always put Li directly inside Ul or Ol, and Dt and Dd directly inside Dl
The elements only make a list when they are nested this way. A Li outside a list, or a Dd outside a Dl, is not announced as part of one.
WCAG: 1.3.1 Info and Relationships
Never type a bullet or a number into the text of a paragraph
A hand-made list has no list structure, so a screen reader cannot say how many items there are or let the user skip it. Use the list components.
WCAG: 1.3.1 Info and Relationships
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 | Partially tested | axe-core via the Storybook test runner (CI) |
| Keyboard navigation | Manually tested | keyboard (reported by the owner) |
| Screen reader | Manually tested | VoiceOver with Chrome (reported by the owner) |
What these tests and statuses mean
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.
The tests
- 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.
The statuses
- 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.