Spinner
A ring that spins while something loads. If you know how long it takes, or how far it has got, Progress is better. This one only says that something is in progress.
How to use it
Section titled “How to use it”<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/tokens/tokens.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/src/components/css/spinner/spinner.css"><!-- Or everything in one file: https://cdn.jsdelivr.net/npm/@lo-tek/interfaces@0.36.0/dist/lotek.css --><span class="lt-spinner" data-size="small" aria-hidden="true"></span><span class="lt-spinner" aria-hidden="true"></span><span class="lt-spinner" data-size="large" aria-hidden="true"></span>import "@lo-tek/interfaces/tokens.css"import "@lo-tek/interfaces/spinner.css"lt is used in two ways, and which one depends on whether you create the element or find it.
If you create the markup, you spread the attributes in. That is the route in React, Astro and anything else that renders:
import { lt } from "@lo-tek/interfaces/react"
<span {...lt.spinner({ size: "small" })} aria-hidden="true" />The import goes to /react here, since the block is JSX. From there the keys are called className and htmlFor. In Astro and anything else without React you import @lo-tek/interfaces and get class and for.
If the element is already there, you set them on it. That is the route when you enhance HTML a server or a template has sent:
import { lt } from "@lo-tek/interfaces"
const ring = document.querySelector<HTMLElement>("#waiting")
lt.setAttributes(ring, lt.spinner({ size: "small", label: "Loading applications" }))label gives both role="status" and aria-label, since the ring has no name without both. If you leave it out, the ring is just a shape. See Type-safe use.
data-size | Used for |
|---|---|
small | Inside a button or a table row |
| (omitted) | Next to a text |
large | In the middle of a page or in a panel that is loading |
With text beside it
Section titled “With text beside it”Someone listening to the page gets nothing from a ring. Let a visible text carry the message. The ring can get a name with aria-label, but it is not certain to be announced by itself; see below.
Fetching your applications
<p role="status"><span class="lt-spinner" data-size="small" aria-hidden="true"></span>Fetching your applications</p>If the text is visible, set aria-hidden="true" on the ring. If the ring also has a name, the wait is otherwise announced twice.
The paragraph is announced when the text is inserted into it. So leave <p role="status"> empty in the page beforehand, and write the ring and the text into it when the wait begins.
The ring is inline-block, so it sits in line with the text by itself. If you want them on the same baseline with a fixed gap, that is the app’s layout: display: flex, align-items: center and gap on the paragraph.
If the ring stands alone, it gets the role and the name itself:
<span class="lt-spinner" role="status" aria-label="Loading applications"></span>That gives the ring a name when someone looks for it, but it is not certain to be announced by itself. A region with role="status" announces changes to its content, and the ring has no content. If it matters that the wait is reported, use the paragraph with text above, in a status element that is in the page before the wait starts.
Inside a button
Section titled “Inside a button”<button class="lt-button" disabled> <span class="lt-spinner" data-size="small" aria-hidden="true"></span> Sending application</button>Let the button text change from “Send application” to “Sending application”. Then the button says what is happening, also for someone who does not see the ring.
Classes you can style
Section titled “Classes you can style”| Class | What it is |
|---|---|
.lt-spinner | The ring. The size comes from data-size. |
| Variable | Default |
|---|---|
--lt-spinner-size | var(--lt-spacing-6) |
--lt-spinner-thickness | 2px |
The variables apply to the default size. data-size="small" and data-size="large" set their own size, and large its own thickness as well.
If the user has asked for reduced motion in their system, the ring spins more slowly. It does not stop completely: an indicator that stands still no longer says that something is in progress.
See Customising for how the variables and the layer work.
Accessibility
Section titled “Accessibility”- Wait a little before you show it. A ring that flashes past in 100 milliseconds is more disturbing than nothing.
- Say what is loading, not just that something is loading. “Fetching your applications” is worth more than “Loading”.
- When the wait is over, move focus to where the result appeared, or report it in a
role="status"element. Otherwise the user is left without knowing that anything happened.