Skip to main content

Empty

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

In Dense data

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Dense data: An empty table says what to do next.

  • 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 Dense data decided and why. Each sample is the live story with that variant set.

defaultvariantNot used in Dense data
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 Dense data

No pictures: an empty table needs the reason and the one action that fills it.

iconvariantUsed in Dense data
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 Dense data

An outline icon in a small tile beside the reason and the action.

How Dense data uses it​

An empty state
Use Why it is empty and the one action that fills it
Not A blank table
An empty table with no words looks like an error. Example: “No escalated alerts. Change the date range to see older ones.”

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.

What is the main content?content.q1
1The answer
Numbers and records

Most of the screen is numbers and records.

2So Empty
  • –does not use default: No pictures: an empty table needs the reason and the one action that fills it.
It also shapes Badge: neutral Badge: info Badge: success Badge: warning Badge: danger Sidebar: default Sidebar: outline Item: default Item: outline Toggle: default Toggle: outline
3If it changed
2
Empty decisions would reopen

and 44 answers that follow from it: A lot, Scan and compare, People keep their place, and 41 more.

Where do the words matter most?voice.lands
1The answer
Errors and empty states

Errors and empty tables are where words decide the next action.

2So Empty
  • –does not use default: No pictures: an empty table needs the reason and the one action that fills it.
It also shapes Toast: danger
3If it changed
1
Empty decision would reopen

No other answer follows from it.

What do icons do?iconography.roles
1The answer
Actions and status

Icons mark row actions and status.

2So Empty
  • ✓uses icon: An outline icon in a small tile beside the reason and the action.
It also shapes Button: icon Input group: inline-start
3If it changed
1
Empty decision would reopen

No other answer follows from it.

What icon style?iconography.definition
1The answer
Outline

Outline icons stay light next to dense text.

2So Empty
  • ✓uses icon: An outline icon in a small tile beside the reason and the action.
3If it changed
1
Empty decision would reopen

No other answer follows from it.

Words​

  • Lead with the object, then the state: "Alert 2041 contained."
  • Use numbers, not words for numbers.
  • One verb per button. No "please", no exclamation marks.
  • Use: Investigate, Filter, Assign, Escalated, Resolved. Avoid: Oops, Awesome, Please, Simply.

The labels components use, from the voice tokens:

  • content.action.commit: Save
  • content.action.cancel: Cancel
  • content.action.destroy: Delete
  • content.action.retry: Retry
  • content.action.empty-action: Change filters

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

Dense data 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.24:1.5rem
Cornercomponent.empty.radiusradius.containervar(--empty-radius)radius.4:0.25rem
Paddingcomponent.empty.paddingcomponent-spacing-map.x6var(--empty-padding)space.24:1.5rem
Padding 2component.empty.padding-2component-spacing-map.x12var(--empty-padding-2)space.48:3rem
Header
Gapcomponent.empty.header.gapspace.gap.defaultvar(--empty-header-gap)space.8:0.5rem
Icon
Cornercomponent.empty.icon.radiusradius.containervar(--empty-icon-radius)radius.4:0.25rem
Fill
Changes with theme
component.empty.icon.backgroundcolor.surface.sunkenvar(--empty-icon-background)Lightslate.light.100:#EEF1F5Darkslate.dark.100:#262D38
Text
Changes with theme
component.empty.icon.labelcolor.text.primaryvar(--empty-icon-label)Lightslate.light.900:#161B23Darkslate.dark.900:#F7F8FA
Title
Text sizecomponent.empty.title.font-sizetype.heading.font-sizevar(--empty-title-font-size)font.size.16:1rem
Weightcomponent.empty.title.font-weighttype.label.font-weightvar(--empty-title-font-weight)font.weight.500:500
Description
Text sizecomponent.empty.description.font-sizetype.body.font-sizevar(--empty-description-font-size)font.size.14:0.875rem
Text
Changes with theme
component.empty.description.labelcolor.text.mutedvar(--empty-description-label)Lightslate.light.600:#535D6DDarkslate.dark.400:#969FAD
Label 2
Changes with theme
component.empty.description.label-2color.action.primaryvar(--empty-description-label-2)Lightviolet.light.600:#4B3FD9Darkviolet.dark.600:#A9A3F6
Content
Gapcomponent.empty.content.gapspace.gap.groupvar(--empty-content-gap)space.16:1rem
Text sizecomponent.empty.content.font-sizetype.body.font-sizevar(--empty-content-font-size)font.size.14:0.875rem