SaveStatus
Autosave readout — Saved / Saving / Unsaved / Couldn't save in a fixed-width slot that never reflows its row, with a retry mark after a failed save. aria-live polite; draws no edge.
npx visor add save-status use-autosaveWith useAutosave
SaveStatus is the readout for useAutosave: pass it the hook's status, and its retry for the retry mark. There is no Save button.
Every state, in a row
The slot has a fixed width (--save-status-width, 7.5rem), so the text after it stays put as the state changes. Saved rests muted; Couldn't save takes the error colour and, when onRetry is passed, a retry mark.
Accessibility
The label sits in a role="status" region with aria-live="polite", so a screen reader hears each change without losing its place. The readout is status text, not a button: the only control is the retry mark (named "Retry saving"; set retryLabel to change it), and it sits outside the live region so it is not announced with every state.
Theming
components.save-status sets the slot: width, font-family, text-transform and letter-spacing. Unset, the readout inherits its family, case and tracking from its row, and any rule of yours wins. A 78px caps mono readout:
components:
save-status:
width: "78px"
font-family: "var(--font-mono)"
text-transform: uppercase
letter-spacing: "0.06em"The retry mark is the icon Button's mark: --button-icon-size, --button-icon-pad (its hit target, which adds no height) and --button-icon-ghost-color. SaveStatus draws no edge, so there is nothing for control.edge-width to turn off.
Installation
npx visor add save-statusThis copies two files into your project:
components/ui/save-status/save-status.tsx: the componentcomponents/ui/save-status/save-status.module.css: the styles
API Reference
SaveStatusProps
| Prop | Type | Default | Description |
|---|---|---|---|
status* | 'saved' | 'saving' | 'unsaved' | 'refused' | — | Where the value stands — pass `useAutosave(...).status`. |
onRetry | () => void | — | Shows a retry mark while `status` is `refused`. Pass `useAutosave(...).retry`. |
labels | Partial<Record<'saved' | 'saving' | 'unsaved' | 'refused', string>> | — | Override any of the four labels (Saved, Saving, Unsaved, Couldn't save), e.g. to translate them. |
retryLabel | string | 'Retry saving' | Accessible name of the retry mark. |
SaveStatus also accepts the standard <span> HTML attributes.
Offline Banner
App-shell banner for network connectivity loss. Non-blocking sticky bar below nav with offline, reconnecting, and restored states.
Slow Network Bar
A 4px indeterminate progress bar that surfaces after a 3 s threshold to signal slow or stalled network requests — without blocking interaction.