Spinner
A small turning mark for a short wait inside one control: a button that is saving, a step Flo is filling. Whole pages and regions use a skeleton instead.
Playground
Change the controls to try each prop. The code under the preview updates as you go and lists only the props you changed; copy it into your page.
import { Spinner } from '@/ui/spinner';<Spinner label="Loading" />Default
A 16px spinner that turns once a second. Screen readers hear "Loading".
import { Spinner } from '@/ui/spinner';
export default function SpinnerDefault() {
return <Spinner />;
}Sizes
Two sizes, matching the icon sizes: 16px by default, and sm at 12px next to 12px text.
import { Spinner } from '@/ui/spinner';
export default function SpinnerSizes() {
return (
<div className="flex items-center gap-300">
<Spinner />
<Spinner size="sm" />
</div>
);
}Colour
The spinner takes the colour of the text around it: ink, subtle, or white on the primary button.
import { Button } from '@/ui/button';
import { Spinner } from '@/ui/spinner';
export default function SpinnerColour() {
return (
<div className="flex items-center gap-300">
<span className="text-text">
<Spinner />
</span>
<span className="text-text-subtle">
<Spinner />
</span>
<Button variant="primary" loading>
Save changes
</Button>
</div>
);
}In a button
Press the button to see it. Pass loading to the button rather than placing a spinner yourself: the spinner covers the label, the width holds and a second press is ignored.
import { useState } from 'react';
import { Button } from '@/ui/button';
export default function SpinnerInAButton() {
const [saving, setSaving] = useState(false);
const save = () => {
setSaving(true);
setTimeout(() => setSaving(false), 2000);
};
return (
<Button variant="primary" loading={saving} loadingLabel="Saving" onClick={save}>
Save changes
</Button>
);
}Inline status
A 12px spinner with a word beside it, for a step that is still running.
import { Spinner } from '@/ui/spinner';
export default function SpinnerInlineStatus() {
return (
<span className="inline-flex items-center gap-050 text-body-small leading-body-small font-medium text-text-subtle">
<Spinner size="sm" label="Flo is filling the CV" />
Flo is filling
</span>
);
}Skeleton
The page's frame at its real sizes, with grey shapes where the data will go. Every route shows one while it loads, so a click answers at once.
Toast
A short note, bottom right, that something just happened: a save, a move, an archive. It states the fact in the past tense and offers Undo when the action can be reversed.