Skip to main content

Empty

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

In Multi-brand

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Multi-brand: No orders yet.

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

defaultvariantNot used in Multi-brand
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 Multi-brand

Shared structure in every brand: no brand pictures in empty states.

iconvariantUsed in Multi-brand
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 Multi-brand

An icon in a small tile, from the one outline set every brand shares.

How Multi-brand uses it​

An empty state
Use Shared structure, brand words
Not A different structure per brand
The structure is the shared core; words carry the brand. Example: “No orders yet. Your first order will appear here.”

Why it works this way​

Empty looks the way it does because of 3 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 is the voice defined?voice.definition
1The answer
A shared core, brand tone on top

Errors and confirmations are shared; brand tone sits on top.

2So Empty
  • –does not use default: Shared structure in every brand: no brand pictures in empty states.
It also shapes Alert: destructive Toast: neutral Toast: danger
3If it changed
1
Empty decision would reopen

No other answer follows from it.

How are brands handled?theming.definition
1The answer
Brands as modes

Brands are theme modes over shared semantics.

2So Empty
  • –does not use default: Shared structure in every brand: no brand pictures in empty states.
It also shapes Sidebar: default Sidebar: outline Item: muted Toggle: outline
3If it changed
1
Empty decision would reopen

No other answer follows from it.

What icon style?iconography.definition
1The answer
Outline

One outline set for every brand.

2So Empty
  • ✓uses icon: An icon in a small tile, from the one outline set every brand shares.
It also shapes Input group: inline-start
3If it changed
1
Empty decision would reopen

No other answer follows from it.

Words​

  • Shared structure: object, state, next step.
  • Brand tone lives in headlines and marketing copy, not in errors.
  • Errors and confirmations read the same in every brand.
  • Use: Get started, Plan, Order. Avoid: Brand-specific words in errors, Jargon.

The labels components use, from the voice tokens:

  • content.action.commit: Save
  • content.action.cancel: Cancel
  • content.action.destroy: Remove
  • content.action.retry: Try again
  • content.action.empty-action: Get started

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

Multi-brand decides what changes when you switch theme. Here a switch changes colors, type and shape, so the marked rows differ between its brands and 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
Corner
Changes with theme
component.empty.radiusradius.containervar(--empty-radius)Aster Lightradius.8:0.5remAster Darkradius.8:0.5remBirch Lightradius.16:1remBirch Darkradius.16:1remCoral Lightradius.20:1.25remCoral Darkradius.20:1.25rem
Paddingcomponent.empty.paddingcomponent-spacing-map.x6var(--empty-padding)space.36:2.25rem
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.12:0.75rem
Icon
Corner
Changes with theme
component.empty.icon.radiusradius.containervar(--empty-icon-radius)Aster Lightradius.8:0.5remAster Darkradius.8:0.5remBirch Lightradius.16:1remBirch Darkradius.16:1remCoral Lightradius.20:1.25remCoral Darkradius.20:1.25rem
Fill
Changes with theme
component.empty.icon.backgroundcolor.surface.sunkenvar(--empty-icon-background)Aster Lightslate-deep.light.100:#F1F5F9Aster Darkslate-deep.dark.100:#1E293BBirch Lightslate-deep.light.100:#F1F5F9Birch Darkslate-deep.dark.100:#1E293BCoral Lightslate-deep.light.100:#F1F5F9Coral Darkslate-deep.dark.100:#1E293B
Text
Changes with theme
component.empty.icon.labelcolor.text.primaryvar(--empty-icon-label)Aster Lightslate-deep.light.900:#0F172AAster Darkslate-deep.dark.900:#F8FAFCBirch Lightslate-deep.light.900:#0F172ABirch Darkslate-deep.dark.900:#F8FAFCCoral Lightslate-deep.light.900:#0F172ACoral Darkslate-deep.dark.900:#F8FAFC
Title
Text sizecomponent.empty.title.font-sizetype.heading.font-sizevar(--empty-title-font-size)font.size.20:1.25rem
Weightcomponent.empty.title.font-weighttype.label.font-weightvar(--empty-title-font-weight)font.weight.600:600
Description
Text sizecomponent.empty.description.font-sizetype.body.font-sizevar(--empty-description-font-size)font.size.16:1rem
Text
Changes with theme
component.empty.description.labelcolor.text.mutedvar(--empty-description-label)Aster Lightslate-deep.light.600:#4B5A6FAster Darkslate-deep.dark.400:#96A3B5Birch Lightslate-deep.light.600:#4B5A6FBirch Darkslate-deep.dark.400:#96A3B5Coral Lightslate-deep.light.600:#4B5A6FCoral Darkslate-deep.dark.400:#96A3B5
Label 2
Changes with theme
component.empty.description.label-2color.action.primaryvar(--empty-description-label-2)Aster Lightteal.light.600:#0F766EAster Darkteal.dark.600:#7FCFC6Birch Lightpurple.light.600:#6D28D9Birch Darkpurple.dark.600:#B79DF7Coral Lightorange.light.600:#C2410CCoral Darkorange.dark.600:#F7A67F
Content
Gapcomponent.empty.content.gapspace.gap.groupvar(--empty-content-gap)space.24:1.5rem
Text sizecomponent.empty.content.font-sizetype.body.font-sizevar(--empty-content-font-size)font.size.16:1rem