Skip to content

Empty State

Explain why a view is empty and help people take the next step.

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use an empty state wherever a list, table or panel can be empty: before the first item exists, when a search matches nothing, and when the content failed to load. Show it where the content would be, so the page keeps its shape and people know where things will appear. Keep full-page failures, like a missing route, for an error page.

import { InboxIcon } from '@youj/icons'
import { Button, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from '@youj/react'

export function NoIssues() {
  return (
    <Empty>
      <EmptyHeader>
        <EmptyMedia variant="icon">
          <InboxIcon />
        </EmptyMedia>
        <EmptyTitle>No open issues</EmptyTitle>
        <EmptyDescription>Issues you create or are assigned will land here.</EmptyDescription>
      </EmptyHeader>
      <EmptyContent>
        <Button>New issue</Button>
      </EmptyContent>
    </Empty>
  )
}

Empty centers its content and fills the space it's given. EmptyHeader holds the media, the title and the description. EmptyContent holds the actions, outside the header. An empty state with nothing to do next, like an inbox at zero, leaves EmptyContent out.

Reference

Propsvariant (1)

Props

EmptyMedia props
PropType
variant'default' | 'icon'

default 'default'

'default'

Empty, EmptyHeader, EmptyTitle and EmptyContent take the props of a div, and EmptyDescription takes those of a p.

MotionPlates fan out, header hover, icon · reduced motion

Motion

Motion tokens
MomentTokens
Plates fan outfrom a neat stack as the media appears
duration.slowease.emphasized

340ms · cubic-bezier(0.6, 0, 0.1, 1)

340mscubic-bezier(0.6, 0, 0.1, 1)
Header hoverthe plates open a few degrees further
duration.slowease.emphasized

340ms · cubic-bezier(0.6, 0, 0.1, 1)

340mscubic-bezier(0.6, 0, 0.1, 1)
Iconplays while the header is hovered
no token

the icon’s own choreography

the icon’s own choreography

Reduced motion

The plates rest fanned and still, and icons hold their resting pose on hover.

The plates rotate about their own bottom corners, so the pair splays like cards in a hand. Only rotate and translate change.

Reduced motion

The plates appear already fanned and don't move on hover, and icons inside hold their resting pose. The layout and the message are the same.

Accessibilityfocus, announcements

Accessibility

  • The plates and the icon are decorative and hidden from assistive technology. The title and description carry the message.
  • EmptyTitle is a div, so it isn't part of the page's outline. When the empty state stands in for a whole panel or page, put a heading inside it, such as <EmptyTitle><h2>No deployments yet</h2></EmptyTitle>.
  • An empty state that replaces content after a search or filter appears without an announcement. Report the change in a polite live region, and keep focus on a control that still exists.
  • Actions sit outside the header, so their icons play only with their own buttons.