Skip to content
SuperCoach

Components · Data display

Empty state

Beta

What to show when there is nothing yet, such as no clients.

No clients yet

Add your first client to assign a program, track check-ins and send invoices.

When to use

  • When a list, table or chart has nothing to show yet: no clients, no check-ins this week, no invoices.
  • When a search or filter matches nothing.
  • When content failed to load and the area would otherwise be blank.

When not to use

  • While content is loading: use a Skeleton. An empty state that flashes before the data arrives tells coaches they have nothing.
  • For an error that affects the whole page or a form: use an Alert.
  • For a single empty cell in a table: show "—" (see Table).
  • For a short confirmation after an action ("Client archived"): use a Toast.

Anatomy

No clients yet

Add your first client to assign a program.
  1. 1. Container: centered, dashed border when it stands in for a list
  2. 2. Media: an icon in a muted tile (optional)
  3. 3. Title: what is empty, as a heading
  4. 4. Description: why, and what to do next
  5. 5. Action: one primary button, with an optional secondary one

shadcn calls the component Empty. Its parts are Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription and EmptyContent (for actions).

Variants

No clients match “Hamad”

Check the spelling, or clear the filter to see all 24 clients.
VariantUse forAction
First useNothing has been created yet: "No clients yet". Explains the value and starts the first task.Primary: "Add client"
No resultsA search or filter matched nothing: "No clients match “Hamad”".Outline: "Clear filter"
ErrorData didn't load: "Check-ins didn't load". Says nothing was lost.Outline: "Try again"

EmptyMedia has two variants: default (no tile, for an illustration) and icon (a 40px muted tile with a 24px icon). Use icon in product UI. For errors, the example tints the tile with bg-destructive-subtle text-destructive-text.

The dashed border comes from border-dashed on the container, but the container sets no border width: add border when the empty state stands in for a list or table, as in the examples. Leave it off inside a card that already has a border.

States

Empty states have no interactive states of their own. The buttons inside follow Button.

StateWhat changesToken
RestMuted icon tile, muted descriptionbg-muted, text-muted-foreground
Link in the description, hoverLink turns to primaryhover:text-primary
ErrorTile in the destructive colors (set in the example, not the component)bg-destructive-subtle, text-destructive-text

Usage guidelines

  • Say what is empty in the title, and what to do in the description. Coaches should never wonder whether something is broken.
  • One primary action, the one that fills the space: "Add client" on an empty client list.
  • For no results, repeat what was searched and offer the way back: "Clear filter".
  • For errors, say what failed, that nothing was lost if that is true, and offer to retry.
  • Keep the surrounding page in place: the page title, filters and tabs stay, so coaches know where they are.
No clients yet
Add your first client to assign a program.
Do.Says what is empty and what to do next.
No data
Don't.“No data” with no way forward. Coaches can't tell whether it's empty or broken.

Content guidelines

  • Title: a short statement in sentence case, no period. "No clients yet", "No check-ins this week", "No clients match “Hamad”". Not "Oops!" and not "No data".
  • Description: one or two sentences. Say why it's empty and what happens when it isn't: "Add your first client to assign a program, track check-ins and send invoices."
  • Action: a verb and an object, as in Button: "Add client", "Clear filter", "Try again".
  • Errors don't blame the coach and don't show error codes: "Check-ins didn't load. Your clients' check-ins are safe. Check your connection and try again."
  • Arabic: keep the same structure. "لا يوجد عملاء بعد" for "No clients yet", and «» quotation marks around a searched term: لا يوجد عميل باسم «حمد».

Accessibility

KeyDoes
TabMoves to the action buttons and any link in the description
Enter or SpaceActivates the focused button
  • EmptyTitle is a div. Put a heading inside it at the right level (<EmptyTitle><h3>No clients yet</h3></EmptyTitle>), so screen reader users find the empty state when they move by headings.
  • The icon is decorative (aria-hidden); the title says it.
  • When an empty state replaces content after an action, announce it. For a filter, a role="status" count ("No results") is enough, as in the Data table. For an error that appears after loading, put role="alert" on the container, as in the error example: screen readers announce "Check-ins didn't load" and the description.
  • After "Clear filter" or "Try again", move focus to the restored content or keep it on a control that still exists, so it isn't lost when the empty state disappears.

RTL

The empty state is centered, so nothing moves. The icon in a button sits before the label (on the right in Arabic). Icons with a direction, such as an arrow in "Go to programs", mirror with rtl:-scale-x-100; the icons used here (people, search, warning, refresh) don't.

Tokens used

Read from components/ui/empty.tsx at build time, so this list changes when the component does. Opacity modifiers such as /90 are shadcn hover and focus tints on top of the token.

Semantic color tokens used by this component
TokenUtilitiesSuperCoachCoach
--foregroundtext-foregroundneutral-950neutral-950
--mutedbg-mutedneutral-100neutral-100
--muted-foregroundtext-muted-foregroundneutral-600neutral-600
--primarytext-primarybrand-600orange-500
  • Radiusrounded-lg
  • Typetext-lg
  • Typefont-medium
  • Typetext-sm
  • Typetracking-tight

Props

<Empty>

Also takes every prop of <div>

No props of its own.

<EmptyHeader>

Also takes every prop of <div>

No props of its own.

<EmptyMedia>

Also takes every prop of <div>

EmptyMedia props
PropTypeDefault
variant"default" | "icon""default"

<EmptyTitle>

Also takes every prop of <div>

No props of its own.

<EmptyDescription>

Also takes every prop of <p>

No props of its own.

<EmptyContent>

Also takes every prop of <div>

No props of its own.

Replaces in coach-admin

From the read-only audit of coach-admin: 58 style values, 71 uses.

coach-admin has a shared EmptyState component, and charts and posts have their own empty styles (.chart-empty-state, .empty-posts-state).

Classes and selectors

  • .empty-state9
  • .empty-state-icon5
  • .empty-state-subtitle4
  • .empty-state-container4
  • .chart-empty-state-icon4
  • .chart-sub-title-empty-state3
  • .chart-empty-state2
  • .empty-state__icon2
  • .empty2
  • .empty-state-title2
  • .finance-section__empty-state2
  • .notes__empty-state-btn2

Files

  • src/components/EmptyState.scss23

The inventory lists the first 12 locations of each value, so file counts are a lower bound.

SCSS variables in these styles

  • $spacing-mdnot a color: spacing, size or layout

Data table, Chart, Skeleton, Alert, Button, Content.