Spinner
For a wait of unknown length. A spinner is an icon, so it takes the icon sizes, 16 to 40 px, and can follow the text it sits in.
Spinner
server - 0 KBFor a wait of unknown length. A spinner is an icon, so it takes the icon sizes, 16 to 40 px, and can follow the text it sits in.
Try it
The code
import { Spinner } from 'topclassui/spinner'
<Spinner />Prefer Skeleton when the shape of what is coming is known; Spinner is for unknown waits.
Every state
3 statesDecorative, in the text colour
Import from the package
import { Spinner } from 'topclassui/spinner'Install once:npm i topclassui@beta zod
Examples
- For a route still loading or a preview still building. When the shape of what is coming is known, a list or a table among them, a Skeleton holds its place instead.
size="custom"sets no size, so the spinner is 1em and grows with the text around it.- To take the colour of the surrounding text instead of a
tone, passclassName="text-current".
Building your preview
import { Spinner } from 'topclassui/spinner'
/** The docs sample, a route-level loading fallback: the text names the wait, so the spinner is hidden. */
export default function Demo() {
return (
<div className="flex items-center justify-center gap-3 py-16">
<Spinner size="lg" aria-hidden />
<p className="text-muted">Building your preview</p>
</div>
)
}
import { Spinner } from 'topclassui/spinner'
/** The five icon steps, 16 to 40 px, each named "Loading" by default. */
export default function Demo() {
return (
<div className="flex flex-wrap items-center gap-3">
<Spinner size="xs" />
<Spinner size="sm" />
<Spinner size="md" />
<Spinner size="lg" />
<Spinner size="xl" />
</div>
)
}
import { Spinner } from 'topclassui/spinner'
/** Each of the six tones at the default size, drawn in the tone's on-soft colour. */
export default function Demo() {
return (
<div className="flex flex-wrap items-center gap-3">
<Spinner tone="primary" />
<Spinner tone="neutral" />
<Spinner tone="success" />
<Spinner tone="warning" />
<Spinner tone="danger" />
<Spinner tone="info" />
</div>
)
}
Retrying the payment
Saving the draft
import { Spinner } from 'topclassui/spinner'
/** text-current replaces the tone, so each spinner takes the colour of the line it sits in. */
export default function Demo() {
return (
<div className="flex flex-col gap-3">
<p className="flex items-center gap-2 rounded-box bg-danger-soft p-3 text-danger-on-soft">
<Spinner size="sm" className="text-current" aria-hidden />
Retrying the payment
</p>
<p className="flex items-center gap-2 text-muted">
<Spinner size="sm" className="text-current" aria-hidden />
Saving the draft
</p>
</div>
)
}
Syncing at text-sm
Syncing at text-lg
Syncing at text-3xl
import { Spinner } from 'topclassui/spinner'
/** custom sets no size, so each spinner is 1em and grows with the type step around it. */
export default function Demo() {
return (
<div className="flex flex-col gap-3 text-body">
<p className="flex items-center gap-2 text-sm">
<Spinner size="custom" aria-hidden />
Syncing at text-sm
</p>
<p className="flex items-center gap-2 text-lg">
<Spinner size="custom" aria-hidden />
Syncing at text-lg
</p>
<p className="flex items-center gap-2 text-3xl">
<Spinner size="custom" aria-hidden />
Syncing at text-3xl
</p>
</div>
)
}
جارٍ تحميل المعاينة
import { ar } from 'topclassui/labels/ar'
import { Spinner } from 'topclassui/spinner'
/** The Arabic labels name the first three; the last sits beside its own text, so it is hidden. */
export default function Demo() {
return (
<div dir="rtl" lang="ar" className="flex flex-col gap-3">
<div className="flex flex-wrap items-center gap-3">
<Spinner labels={ar} size="sm" />
<Spinner labels={ar} />
<Spinner labels={ar} size="lg" tone="neutral" />
</div>
<p className="flex items-center gap-2 text-body">
<Spinner size="sm" aria-hidden />
جارٍ تحميل المعاينة
</p>
</div>
)
}
Props
Keyboard and accessibility
Nothing to operate: it is not interactive on its own.
- Named but silent: an image named by
labels.common.loading, or your ownaria-label, with no live region. - Beside text that already names the wait, pass
aria-hiddenso the wait is not read twice. - In forced colours it takes the system text colour of its parent, so it stays visible in Windows high contrast, and reduced motion stops the turn.
Right to left
The circle turns the same way in both directions: it is never flipped. With the Arabic labels its default name is Arabic too.
Server and client
Renders on the server and ships no JavaScript.
Files: index.tsx.
On the chip: server - 0 KB.