Skip to main content

What it is

A ProgressBar is a horizontal track that fills to show completion. It has two distinct jobs bundled into one component, switched by its variant prop: determinate, where a real 0–100 value fills the bar to an exact point (“how much longer”), and indeterminate, where the bar animates with no real value behind it (“still working, duration unknown”). That determinate/indeterminate split is what separates it from the other two loading primitives in this category. A Skeleton promises a shape, not a percentage. A Spinner is a compact, always-indeterminate mark that fits inline rather than a full-width track. ProgressBar is the only one of the three that can report a real, measurable number.

Live example

Exports

Verified directly from Progress/LinearProgress.tsx, which adds nothing to the interface it wraps — no per-component prop emitter exists yet for this concept, so this table is hand-confirmed rather than generated.
The package exports this as LinearProgress, not ProgressBar. This page’s name is the design vocabulary’s term for the concept; LinearProgress is the import. This is the same pattern TITAN-DIV-10 records for Table/DataGrid, Switch/Toggle, and others, and it already lists this exact mapping — ProgressBar is LinearProgress.

Vocabulary

buffer and query exist in the type system and render nothing Titan has themed or demonstrated. They accept the framework’s own defaults with no Titan color mapping and no story exercising them — more renders than the system has decided about. Treat them as unsupported until a story or override says otherwise.

Choose ProgressBar when

  • The process has a real, trackable length, and you can report a percentage as it advances.
  • Or: something is running with no known duration, and a full-width horizontal indicator fits the layout better than a compact circular one.

Choose something else when

Anatomy

There is no built-in percentage label. The published “with value label” story composes LinearProgress with a separate Typography element by hand, positioned beside the bar. A visible “50%” next to the track is a pattern to build, not a prop to set.

Variants, sizes, and states

The default color renders green, not the brand blue. Progress.overrides.ts maps barColorPrimary to background-success. A ProgressBar with no color prop set — which is most of them, since primary is the default — fills with the same green used for success states elsewhere in the product, not a neutral or brand-colored bar. This is easy to miss because nothing about “just add a progress bar” suggests picking a color.
Two demonstrated variantsdeterminate and indeterminate — and two named colorsprimary (green) and secondary, which resolves to the dedicated progress-bar-secondary token. error, info, success, and warning are accepted by the type but not confirmed to route through a Titan-named token the way primary/secondary do. No size prop. Track height comes entirely from the progress-track-height token, uniform across every use — there is no small/medium distinction the way Button or TextField have one.

Edge and failure states

Tokens

Verified directly from Progress.overrides.ts — no per-component token emitter exists yet for this concept, so this table is hand-confirmed rather than generated.
error, info, success, and warning as explicit color values are not covered by this override file. Only barColorPrimary and barColorSecondary are styled here. Whether those other four route through a Titan-decided token or the framework’s own default palette is unconfirmed — see Open issues.

Composition

No Titan component in this codebase composes LinearProgress internally — it was not found inside any other component’s source during this pass. Its own stories compose it directly with Box for width and, in one case, Typography for a value label; both are call-site patterns, not something the component provides.

Content

A ProgressBar carries no text of its own. If a percentage or a status line accompanies it, it is separate content placed beside the bar — write it the way any other short status line is written, stating what’s in progress, not restating “loading.”

Accessibility

Renders role="progressbar" unconditionally, confirmed directly in the underlying component’s source. In determinate mode it also sets aria-valuenow, aria-valuemin (0), and aria-valuemax (100) from the real value — confirmed in the same source. In indeterminate mode none of the three aria-value* attributes are set, which is the correct behavior for a progressbar with no real value to report. No accessible name is set by the component itself. A ProgressBar describing a specific region’s loading state needs an aria-label or an aria-describedby pointing at it — not supplied automatically, and not verified anywhere in Titan source as a pattern any component uses.

Constraints

Known issues

ProgressBar: open issues

Divergences, open decisions, and undocumented gaps for ProgressBar.

Why it works this way

Determinate and indeterminate are one component because they are the same visual object at different levels of information. Both are a horizontal track; the only difference is whether something outside the component can say how full it should be. Splitting them into two components would duplicate the track, the height token, and the color mapping for a difference that is really just “is value meaningful right now.” The green default is inherited, not chosen for this purpose. Nothing in the override file’s history explains why primary was mapped to background-success specifically for progress bars; it is the same convention this checkout uses for the Loader’s bouncing-bar animation color, which suggests a house habit of coloring “things that are working” green rather than a decision made about ProgressBar on its own.

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.
The generated adoption report for this component shows zero usages, matched against a literal <Progress /> JSX tag — which is not the real import name. Since the actual export and call sites use LinearProgress, this figure is very likely a tag-matching artifact rather than evidence the component is genuinely unused anywhere in the product. Treat it as unreliable rather than as a recommendation either way.
  • Skeleton · Spinner — the other two loading primitives, split by whether the shape or the duration is known
  • Loader — a separate, unrelated component in this same package (a five-bar bounce animation, not a track), heavily adopted across applications per its own generated usage data, and currently undocumented in this site. Not the same thing as this page and not interchangeable with it.
Last modified on September 7, 2026