Status
Activity Indicator
Show that something is happening when there's nothing to measure.
import { ActivityIndicator } from "macbetter/activity-indicator"
export default function Example() {
return (
<div style={{ display: "flex", alignItems: "center", gap: 32, color: "var(--mb-label-secondary)" }}>
<ActivityIndicator size="sm" />
<ActivityIndicator />
<ActivityIndicator size="lg" />
</div>
)
}When to use it
Use an activity indicator for a short wait whose length you can't tell: loading a list, signing in, fetching a preview. If you know how far along the work is, use a progress bar instead, because a bar tells people how long to wait.
Keep it near what's loading, and say what's happening beside it when there's room. Remove it as soon as the content arrives, and don't show one for waits under about a second; a flash of a spinner reads as a glitch.
Usage
import { ActivityIndicator } from "macbetter/activity-indicator"It draws in currentColor, so it matches the text around it. Apple's is gray: put it in secondary label color, as in these demos.
With a label
When text beside it already says what's loading, give the indicator the same words as its aria-label and hide the text from screen readers, so it's read once.
import { ActivityIndicator } from "macbetter/activity-indicator"
export default function Example() {
return (
<div
style={{
display: "flex",
alignItems: "center",
gap: 8,
color: "var(--mb-label-secondary)",
}}
>
<ActivityIndicator aria-label="Loading messages" />
<span aria-hidden="true">Loading Messages…</span>
</div>
)
}Color
On a dark overlay, or in the accent, set the color on a parent.
import { ActivityIndicator } from "macbetter/activity-indicator"
export default function Example() {
return (
<div style={{ display: "flex", alignItems: "center", gap: 24 }}>
<span style={{ color: "var(--mb-label)" }}>
<ActivityIndicator size="lg" aria-label="Preparing export" />
</span>
<span style={{ color: "var(--mb-accent-text)" }}>
<ActivityIndicator size="lg" aria-label="Syncing" />
</span>
<span
style={{
display: "inline-grid",
placeItems: "center",
width: 88,
height: 88,
borderRadius: 20,
background: "rgb(0 0 0 / 0.72)",
color: "#ffffff",
}}
>
<ActivityIndicator size="lg" aria-label="Processing video" />
</span>
</div>
)
}Platform behavior
The sizes follow each platform's native ones. On macOS, sm, md and lg are 12, 16 and 32 points, the mini, small and regular spinning indicators. On iOS and iPadOS they're 16, 20 and 37 points, UIActivityIndicatorView's medium and large.
The spokes are capsules, as on iOS 13 and later and macOS 11 and later. Each one lights fully and then fades until its turn comes round again, so the bright spoke travels clockwise with a fading tail. It keeps turning with Reduce Motion on, as the system spinner does: the motion is the message.
Accessibility
- It's an indeterminate
progressbar, named "Loading" unless you give it anaria-label. Name it for what's loading when that helps: "Loading messages". - It never takes focus.
- If the loading region should be announced as busy, set
aria-busyon that region.
API
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "md" | The platform's mini, small and regular sizes. |
aria-label | string | "Loading" | What's loading. |
It takes ui-sdk Progress props other than value.
| Attribute or variable | On | Description |
|---|---|---|
data-indeterminate | .mb-activity-indicator | Always present, from ui-sdk. |
data-size | .mb-activity-indicator | The size. |
--mb-activity-indicator-duration | .mb-activity-indicator | How long one turn takes. 0.8s by default. |
--mb-activity-indicator-size-sm, --mb-activity-indicator-size, --mb-activity-indicator-size-lg | any ancestor | The three sizes. |