What it is
A Spinner is a small circular mark that animates continuously to show that something is working. It carries no information beyond “in progress” — no percentage, no shape of what’s coming, nothing about how much longer. It has one form: indeterminate. There is a determinate mode in the underlying type interface, but nothing in this codebase demonstrates or themes it — see Variants, sizes, and states. That single-purpose narrowness is what separates it from its two neighbors in this category. A ProgressBar can show a real value; a Spinner never does. A Skeleton previews the shape of content that hasn’t arrived; a Spinner previews nothing about shape at all — it is for a wait too small, too compact, or too shapeless for either of those to fit.Live example
Exports
Verified directly fromCircularProgress.overrides.ts and the package’s top-level export list —
no per-component prop emitter exists yet for this concept, so this table is hand-confirmed
rather than generated.
Choose Spinner when
- Something is working, its duration is unknown, and there is no shape of incoming content to preview.
- The space available is small or inline — a button, a compact region, a line of text — where a full-width ProgressBar would not fit.
Choose something else when
Anatomy
One element: a spinning ring. There is no label slot, no icon, and no container — a caption or surrounding message, if one is needed, is separate content placed beside it.Variants, sizes, and states
One variant demonstrated: indeterminate.determinate exists in the type interface and is
un-themed and un-storied. One themed color: primary. The other five accepted color values
were not confirmed to route through any Titan-named token — CircularProgress.overrides.ts
themes only colorPrimary.
No size scale. size is a raw pixel number or CSS-unit string with no Titan-decided
small/medium/large tier — whatever number is passed renders at that size.
Edge and failure states
No Titan test file exists for this component (there is no
.test.tsx in its source
directory), and no story exercises it — so nothing here is confirmed against this codebase’s
own tests. The table below states what the underlying framework’s own type contract and
source code say, not what Titan has verified.Tokens
Verified directly fromCircularProgress.overrides.ts — no per-component token emitter exists
yet for this concept, so this table is hand-confirmed rather than generated.
Composition
No Titan component in this codebase composesCircularProgress internally — it was not found
inside any other component’s source during this pass. It is not used inside Button’s loading
state, LoaderOverlay, or any other component checked.
Content
A Spinner carries no text. If a wait needs an explanation, put it beside the spinner as separate content — never inside it, and never a “Loading…” label overlapping the mark itself.Accessibility
Rendersrole="progressbar" unconditionally, confirmed directly in the underlying
component’s source — the same as LinearProgress. In indeterminate mode (the only mode this
codebase demonstrates), no aria-valuenow/min/max are set, which is correct for a value that
doesn’t exist.
No accessible name is set by the component itself. The underlying framework’s own
documentation for this component states that a spinner describing a specific region’s loading
state should be paired with aria-describedby pointing at it, and the region itself should carry
aria-busy. Neither is wired up automatically by anything in this codebase — it is a pattern to
apply at the call site, not something the component provides.
Constraints
Known issues
Spinner: open issues
Divergences, open decisions, and undocumented gaps for Spinner.
Why it works this way
A Spinner says less than a ProgressBar on purpose. The moment a process can report real progress, a bar communicates more — which is why nothing in this codebase pairs a determinate value with the circular form. The circular mark is reserved for exactly the case where there is nothing more specific to say than “working.” Its size taking a raw number rather than a themed scale is a real gap, not a deliberate minimalism. Compare ProgressBar, which has no size prop either but is at least pinned to one uniform track-height token — a Spinner has neither a scale nor a single decided size, so every call site picks its own number.Status
No lifecycle metadata exists. There is no
status, since, deprecated, or
replacedBy field on a Titan component, so this table cannot report when an export arrived or
whether it is on the way out.Related
The generated adoption report for this component shows exactly one usage, in a single application. Unlike the Toast and ProgressBar figures elsewhere in this category, this count is not suspected of a tag-matching problem — the real import name (CircularProgress) matches what
the report looked for. Genuinely low adoption, not an artifact of the measurement.
- ProgressBar · Skeleton — the other two loading primitives, split by whether a value or a shape is known
Loader— a separate, unrelated component in this same package that is this codebase’s actual heavily-adopted loading indicator, and has no page in this documentation yet; see the warning above