Susegad UI
Register
Theme
Palette

Components

Empty state

What a place shows before there is anything in it: your heading, sentence and action, named as a region. Quiet adds a hairline drawing; warm sets a scene (Paus, rain on a Goan window) beside the words, drifting slowly; playful lets you play with it. The scene loads only when a warm or playful page needs it.

quiet warm playful

Open the live demo npx susegad add empty

Stands on: Core, Core: components, Paus, Tokens

The prompt

the prompt

Before there is anything here, the rain on the window.

What a place shows before there is anything in it: a heading, a sentence about what will appear there, and the one thing to do next. The words are yours and work without JavaScript. The register brings the picture. Quiet draws a small window in pencil, warm lets a scene drift beside the words, and playful lets you play with it.

<link rel="stylesheet" href="susegad/components/empty/empty.css">
<script type="module" src="susegad/components/empty/empty.js"></script>

<sg-empty scene="paus" scene-intensity="0.55">
  <h2>No bookings yet</h2>
  <p>When a guest books a room, their stay shows up here with the dates and what they asked for.</p>
  <a href="/share">Share your listing</a>
</sg-empty>

The prompt

Build an empty state as a light-DOM custom element, <sg-empty scene="paus">, whose heading, sentence and action are ordinary children, so it reads and works without JavaScript. Gather the children into one body, give the element role="region" named by its heading with aria-labelledby, and pass any scene-<param> attribute through to the scene as <param>. Give it three registers. Quiet: a small hairline drawing of the scene beside the words, drawn once in SVG with non-scaling strokes in the soft ink colour and never moving. For Paus that is the window: an oyster-shell strip, two panes, a sill, a few drops and one runner's trail. Warm: load the scene only now, as an <sg-scene> with its name and params set before it connects, and place it beside the words on a wide box and above them on a narrow one, never behind the text. It follows the page's register, so it drifts slowly, pauses off screen, keeps its own pause button and name for screen readers, and shows its finished still under reduced motion. Playful: the same scene, playing in full and there to be played with; the scene makes itself focusable and reads out how to use it. A quiet page never downloads the scene. Keep the picture as weather: an empty state has nothing in progress, so nothing in it should suggest that something is loading or on its way.

Words to code

When you sayTechniqueWhat happens
ordinary children, so it reads and works without JavaScriptprogressive enhancementThe heading, words and link are plain HTML. Without JavaScript the stylesheet gives them a hairline card and room to breathe.
role="region" named by its headingaccessibilityThe element gives the heading an id if it has none and points aria-labelledby at it, so the region is announced by its words, "No bookings yet".
pass any scene-<param> attribute throughattribute pass-throughscene-intensity="0.55" becomes intensity="0.55" on the <sg-scene>. A MutationObserver forwards changes, so a server can swap one with no glue code.
drawn once in SVG with non-scaling strokeshairline artThe window is plain path data from a pure function. vector-effect: non-scaling-stroke keeps every line one pixel wide at any size.
load the scene only nowlazy loadingThe warm and playful skins import <sg-scene> and the scene module when they mount. The quiet skin imports neither.
beside the words on a wide box and above them on a narrow onelayoutFlexbox with wrapping: the scene and the words each have a basis, and on a narrow box the words drop below the picture instead of covering it.
keeps its own pause button and nameaccessibilityThe backdrop is a real <sg-scene>, so everything the scene contract promises comes with it: a pause button, the still for reduced motion, pausing off screen, and keyboard help in playful.

<sg-empty> is what a place shows before there is anything in it. You write the words; the register brings the picture.

Usage

<link rel="stylesheet" href="susegad/components/empty/empty.css">
<script type="module" src="susegad/components/empty/empty.js"></script>

<sg-empty scene="paus">
  <h2>No messages</h2>
  <p>Guests can write to you from their booking. Their messages arrive here.</p>
  <button type="button">Write a welcome note</button>
</sg-empty>

Write three things: a heading that says what is empty, one sentence about what will appear and when, and the one action that moves things on. Avoid "Nothing to see here". Say what will be here.

Attributes and properties

NameTypeWhat it does
scenescene name (default paus)The scene for warm and playful, and the drawing for quiet. Any scene in susegad/scenes/ works; quiet has a drawing for Paus and a plain tray for the rest.
scene-<param>textPassed to the scene as <param>, for example scene-intensity="0.5", scene-fog="0.9" or scene-seed="4". Changes are forwarded as they happen.
registerquiet, warm or playfulOverrides the page's register for this element.

Registers

  • Quiet: a small hairline drawing beside the words. Nothing moves, and the scene is never downloaded.
  • Warm: the scene beside the words (above them on a narrow box), drifting slowly. It has its own pause button and pauses off screen.
  • Playful: the scene in full, and interactive. In Paus you can wipe the fogged glass with a finger, the pointer or the arrow keys.
  • Reduced motion: the scene shows its finished still. Its play button still plays it for anyone who asks.

Accessibility

  • The element is a region named by its heading. Without a heading it has no role.
  • The words and action are your own HTML, in reading order, and never sit over the picture.
  • In warm, the scene is an image with its own name. In playful it is a focusable interactive drawing with help text, reached by Tab before your action.
  • The quiet drawing is aria-hidden.

What moves, and why

An empty state has no progress to show. The scene is weather: it never suggests that something is loading or about to arrive. If something is loading, use a skeleton or a loader instead.