Skip to main content

Empty

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

In Brand expressive

See it live​

Start Storybook to see it live: npm run storybook

When to use it​

In Brand expressive: A region that loaded with nothing, in playful words with a clear next step. Not while images load; skeleton does that.

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

defaultvariantUsed in Brand expressive
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 Brand expressive

A campaign image or illustration beside the playful words and a clear next step.

iconvariantUsed in Brand expressive
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 Brand expressive

A two-tone icon in a tile, for a small region where a picture would push the words away.

How Brand expressive uses it​

An empty state
Use Playful, with a clear next step
Not A dead end
Playful words still need a way forward. Example: “Nothing here yet. Go find something you love.”

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
Images and campaigns

Images, campaigns and short punchy copy.

2So Empty
  • ✓uses default: A campaign image or illustration beside the playful words and a clear next step.
It also shapes Badge: info Input group: block-start Input group: block-end
3If it changed
1
Empty decision would reopen

and 10 answers that follow from it: One idea at a time, Browse and explore, Regular, and 7 more.

What must the interface protect?human.q1
1The answer
Delight

Delight is the point.

2So Empty
  • ✓uses default: A campaign image or illustration beside the playful words and a clear next step.
3If it changed
1
Empty decision would reopen

and 1 answer that follow from it: Fast.

What icon style?iconography.definition
1The answer
Two-tone

Two-tone icons carry the brand color.

2So Empty
  • ✓uses icon: A two-tone icon in a tile, for a small region where a picture would push the words away.
3If it changed
1
Empty decision would reopen

No other answer follows from it.

What do icons do?iconography.roles
1The answer
Those and decoration

Icons also decorate campaign pages.

2So Empty
  • ✓uses icon: A two-tone icon in a tile, for a small region where a picture would push the words away.
It also shapes Button: ghost Button: icon Input group: inline-start
3If it changed
1
Empty decision would reopen

and 1 answer that follow from it: Two.

Words​

  • Headlines are short and bold. Three to six words.
  • Verbs that move: Join, Try, Go.
  • Playful in headlines, plain in errors.
  • Use: Join, Drop, Go, Love. Avoid: Synergy, Leverage, Kindly.

The labels components use, from the voice tokens:

  • content.action.commit: Go
  • content.action.cancel: Not now
  • content.action.destroy: Remove
  • content.action.retry: Try again
  • content.action.empty-action: Explore the drop

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

Brand expressive 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.64:4rem
Cornercomponent.empty.radiusradius.containervar(--empty-radius)radius.24:1.5rem
Paddingcomponent.empty.paddingcomponent-spacing-map.x6var(--empty-padding)space.48:3rem
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.24:1.5rem
Fill
Changes with theme
component.empty.icon.backgroundcolor.surface.sunkenvar(--empty-icon-background)Lighttaupe.light.100:#FCEFE6Darktaupe.dark.100:#33241F
Text
Changes with theme
component.empty.icon.labelcolor.text.primaryvar(--empty-icon-label)Lighttaupe.light.900:#1F1411Darktaupe.dark.900:#FFF8F3
Title
Text sizecomponent.empty.title.font-sizetype.heading.font-sizevar(--empty-title-font-size)font.size.28:1.75rem
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.17:1.0625rem
Text
Changes with theme
component.empty.description.labelcolor.text.mutedvar(--empty-description-label)Lighttaupe.light.600:#6B544ADarktaupe.dark.400:#B5988A
Label 2
Changes with theme
component.empty.description.label-2color.action.primaryvar(--empty-description-label-2)Lightpink.light.600:#D61F7ADarkpink.dark.600:#F59ACA
Content
Gapcomponent.empty.content.gapspace.gap.groupvar(--empty-content-gap)space.40:2.5rem
Text sizecomponent.empty.content.font-sizetype.body.font-sizevar(--empty-content-font-size)font.size.17:1.0625rem