---
title: Feedback
description: Spinners, skeletons, fading in, empty states and toasts.
---

## Loading

Anything that loads data shows a skeleton shaped like what's coming, so the layout doesn't jump when it arrives. A spinner is the last resort, for an action in progress such as a button that's saving, where there's no shape to stand in for.

<Demo id="loading-components" layout="stack">
  <gw-grid style="--gw-grid-min: 16rem">
    <gw-card heading="Living room" loading></gw-card>
    <gw-card loading lines="2"></gw-card>
  </gw-grid>
  <gw-row>
    <gw-badge label="CPU" loading></gw-badge>
    <gw-badge loading></gw-badge>
    <gw-chip loading></gw-chip>
  </gw-row>
  <gw-row>
    <gw-gauge label="CPU" loading></gw-gauge>
    <gw-gauge label="Memory" caption="52 of 64 GB" loading></gw-gauge>
  </gw-row>
  <gw-meter label="Disk" loading></gw-meter>
  <gw-facts loading rows="3"></gw-facts>
  <div>
    <gw-setting-row heading="Wake on LAN" description="Turn the machine on over the network" loading></gw-setting-row>
    <gw-setting-row loading></gw-setting-row>
  </div>
</Demo>

Set `loading` on a card, badge, chip, gauge, meter, facts or setting row. Whatever is already known, such as a heading or label, stays, and skeletons fill the rest. Each marks itself `aria-busy`.

For a layout of your own, build it from the shapes. They all extend `gw-skeleton`, so they share its color, pulse and reduced-motion handling:

<Demo id="skeleton-shapes" layout="stack">
  <gw-row>
    <gw-skeleton-icon></gw-skeleton-icon>
    <gw-skeleton-text style="--gw-skeleton-width: 10rem"></gw-skeleton-text>
  </gw-row>
  <gw-skeleton-lines lines="3"></gw-skeleton-lines>
  <gw-skeleton style="height: 6rem"></gw-skeleton>
</Demo>

| Element | What it stands in for |
| --- | --- |
| `gw-skeleton` | Anything, sized in CSS, such as an image or chart. Set `--gw-skeleton-radius` to match |
| `gw-skeleton-text` | A line of text, 1em tall so it follows the font size; width from `--gw-skeleton-width` |
| `gw-skeleton-lines` | A paragraph of `lines` lines, the last one shorter |
| `gw-skeleton-icon` | An icon or avatar, sized by `--gw-icon-size` |

Skeletons are hidden from assistive technology, so mark the region they're in `aria-busy`, as the components above do.

## Fading in

<Demo id="fade-in" layout="stack">
  <gw-row>
    <gw-button data-replays variant="neutral" appearance="outlined" size="small" icon="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z">Play again</gw-button>
  </gw-row>
  <gw-grid style="--gw-grid-min: 16rem">
    <gw-fade-in delay="200">
      <gw-card heading="Desktop">
        <gw-facts items='[{"label":"Uptime","value":"3 days, 4 hours"},{"label":"Version","value":"5.2.0"}]'></gw-facts>
      </gw-card>
    </gw-fade-in>
    <gw-fade-in delay="500" duration="350">
      <gw-card heading="Laptop">
        <gw-facts items='[{"label":"Uptime","value":"6 hours"},{"label":"Version","value":"5.2.0"}]'></gw-facts>
      </gw-card>
    </gw-fade-in>
  </gw-grid>
</Demo>

`gw-fade-in` waits `delay` milliseconds, then fades its content in over `duration` (`--gw-motion-slow` by default), easing in and out so it never pops. Use it for most content that arrives after the page:

- Wrap a skeleton with a `delay` of about 500ms, so a load that finishes quickly never flashes a placeholder.
- Wrap the loaded content with no delay, so it eases in where the skeleton was.
- Wrap a page or panel body that appears after a navigation.

It keeps its size while hidden, so nothing around it moves, and the tokens stylesheet hides it until the element is defined, so its content never flashes before the fade. `replay()` fades it out, then runs the wait and fade again. With reduced motion it still waits, then shows at once.

## Spinner

<Demo id="spinner">
  <gw-row><gw-spinner label="Saving"></gw-spinner> Saving</gw-row>
</Demo>

For an action in progress, never for content loading. It's announced by its `label`.

## Empty state

<Demo id="empty-state" layout="stack">
  <gw-empty-state heading="Nothing to apply" icon="M19 3H5A2 2 0 0 0 3 5V19A2 2 0 0 0 5 21H19A2 2 0 0 0 21 19V5A2 2 0 0 0 19 3M5 19V17H8.13A4.13 4.13 0 0 0 9.4 19M19 19H14.6A4.13 4.13 0 0 0 15.87 17H19M19 15H14V16A2 2 0 0 1 10 16V15H5V5H19Z">
    <p>Every item is up to date.</p>
    <gw-button slot="actions" size="small" appearance="filled">Check again</gw-button>
  </gw-empty-state>
</Demo>

What a list or page shows when it's empty or there's nothing to do. Say so in one line, the same as a CLI does.

## Toast

<Demo id="toast">
  <gw-button variant="success" appearance="filled" data-toast="Backup finished" data-tone="success">Finish a backup</gw-button>
  <gw-button variant="warning" appearance="filled" data-toast="Disk nearly full" data-tone="warning">Fill a disk</gw-button>
  <gw-toaster duration="4000"></gw-toaster>
</Demo>

Put one `gw-toaster` on the page and call `show(message, tone)`. Each toast is announced politely and leaves after `duration` milliseconds. Toasts are for something new that needs the person, not for routine success.
