Skip to main content

Empty

What a region shows when it loaded and has nothing: why, and what to do next.

In Accessible first

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Accessible first: An empty list, saying what will appear and how to start. Not while loading, and never a blank page.

  • Use it when: An empty list, a search with no results, or a first visit with no items yet.
  • Not when: Still loading (skeleton or spinner), or a load that failed (alert).

Instead:

Variants​

What each variant is for in any design system, then what Accessible first decided and why. Each sample is the live story with that variant set.

defaultvariantNot used in Accessible first
Start Storybook to see it live

What it is for

The picture shown as it is: an image or illustration.

✓A larger empty area where a picture helps.
✕A small region where the picture would push the words away.

In Accessible first

The brand stays out of the way: words say what will appear and how to start.

iconvariantUsed in Accessible first
Start Storybook to see it live

What it is for

The picture as an icon in a small tile.

✓A compact empty state next to data.
✕A first visit that needs more warmth than an icon.

In Accessible first

A filled icon in a tile, beside words that say what will appear here and how to start.

How Accessible first uses it​

An empty state
Use Explain what will appear here and how to start
Not A blank page
A blank page leaves people unsure if something failed. Example: “You have no saved applications. Start a new one below.”

Why it works this way​

Empty looks the way it does because of 4 answers about this product. Each card is one answer, in three steps: the answer, what it decided for Empty, and what would move if it changed.

How visible is the brand in the interface?brand.q2
1The answer
Quiet

The brand stays out of the way.

2So Empty
  • –does not use default: The brand stays out of the way: words say what will appear and how to start.
3If it changed
1
Empty decision would reopen

No other answer follows from it.

What must the interface protect?human.q1
1The answer
Low effort to understand

Low effort to understand each step.

2So Empty
  • –does not use default: The brand stays out of the way: words say what will appear and how to start.
It also shapes Alert: default
3If it changed
2
Empty decisions would reopen

and 15 answers that follow from it: Calm and clear, Quiet, Core: heading, body, label, and 12 more.

What icon style?iconography.definition
1The answer
Filled

Filled icons stay visible at low vision.

2So Empty
  • ✓uses icon: A filled icon in a tile, beside words that say what will appear here and how to start.
3If it changed
1
Empty decision would reopen

No other answer follows from it.

How does it sound?voice.values
1The answer
Plain and direct

Every sentence is easy to read on the first try.

2So Empty
  • ✓uses icon: A filled icon in a tile, beside words that say what will appear here and how to start.
It also shapes Alert: destructive
3If it changed
1
Empty decision would reopen

No other answer follows from it.

Words​

  • Use common words. Explain any term you must use.
  • One idea per sentence. Put the action first.
  • Never blame the person.
  • Use: Continue, Change, Start, You. Avoid: Invalid, Utilise, Submit, Error code.

The labels components use, from the voice tokens:

  • content.action.commit: Continue
  • content.action.cancel: Go back
  • content.action.destroy: Delete
  • content.action.retry: Try again
  • content.action.empty-action: Start a new application

See Voice and tone for the whole voice.

Use it in code​

npx open-ds add empty

The component reads only component keys and semantic tokens, so it follows the brand and mode on <html>.

Tokens it reads​

Empty reads 15 tokens of its own, each an alias of a semantic token. Each row is one part: its own token, the semantic it aliases, and the value it ends at. Change a semantic and every component that reads it follows; override one of Empty's tokens to change Empty alone.

Changes with theme

Accessible first decides what changes when you switch theme. Here a switch changes colors only, so the marked rows differ between light and dark; everything else holds steady.

PartIts token and the semantic it aliasesValue
Empty
Gapcomponent.empty.gapspace.gap.sectionvar(--empty-gap)space.48:3rem
Cornercomponent.empty.radiusradius.containervar(--empty-radius)radius.8:0.5rem
Paddingcomponent.empty.paddingcomponent-spacing-map.x6var(--empty-padding)space.44:2.75rem
Padding 2component.empty.padding-2component-spacing-map.x12var(--empty-padding-2)space.64:4rem
Header
Gapcomponent.empty.header.gapspace.gap.defaultvar(--empty-header-gap)space.16:1rem
Icon
Cornercomponent.empty.icon.radiusradius.containervar(--empty-icon-radius)radius.8:0.5rem
Fill
Changes with theme
component.empty.icon.backgroundcolor.surface.sunkenvar(--empty-icon-background)Lightgray.light.100:#EDEDEDDarkgray.dark.100:#222222
Text
Changes with theme
component.empty.icon.labelcolor.text.primaryvar(--empty-icon-label)Lightgray.light.900:#141414Darkgray.dark.900:#F7F7F7
Title
Text sizecomponent.empty.title.font-sizetype.heading.font-sizevar(--empty-title-font-size)font.size.22:1.375rem
Weightcomponent.empty.title.font-weighttype.label.font-weightvar(--empty-title-font-weight)font.weight.700:700
Description
Text sizecomponent.empty.description.font-sizetype.body.font-sizevar(--empty-description-font-size)font.size.19:1.1875rem
Text
Changes with theme
component.empty.description.labelcolor.text.mutedvar(--empty-description-label)Lightgray.light.500:#595959Darkgray.dark.500:#949494
Label 2
Changes with theme
component.empty.description.label-2color.action.primaryvar(--empty-description-label-2)Lightblue.light.600:#0B4FC0Darkblue.dark.600:#8AB4F8
Content
Gapcomponent.empty.content.gapspace.gap.groupvar(--empty-content-gap)space.32:2rem
Text sizecomponent.empty.content.font-sizetype.body.font-sizevar(--empty-content-font-size)font.size.19:1.1875rem