GrProgressBar
Shows the progress of a task or a loading process.
Overview
When to take it
- the share of what is done is known — an import, a file upload, a step of a wizard: the bar answers “how much is left”;
- the end is unknown —
indeterminateshows that the process is running without promising a deadline; - more has been loaded than played —
bufferdraws a second layer: video buffering, prefetching; - the value has to be shown in words —
showValuewithformatValueinstead of a separate caption.
When to take something else
| Need | Take |
|---|---|
| There is no room across the width | GrProgressCircle |
| The share is unknown and the content is already there | GrLoading |
| There is no content yet | GrSkeleton |
| The progress of a file upload | GrFileUpload |
| Show a share of a whole as data | GrChartPie |
Variants every tone and view, rendered by the real component
tone
primaryneutralsuccesswarningdangerinfoslateazure
Sizes
xssmmdlg
Playground controls come from the API, not from hand
Loading…
0 changed· state is in the URL
<GrProgressBar :value="64" showValue />Examples 5 each with a live demo and its code
Progress in the reader’s units
The import counts rows, so the label does too:
format-valueturns the share into «1,140 of 3,000 rows» and hands the same text toaria-valuetext.aria-labelnames the process — without it the reader hears a number with no subject. At the end the tone becomes the verdict.Importing customerscustomers-2026-10.csv · matching by tax ID1,140 of 3,000 rowsTone as a verdict
The same bar reads differently by tone:
primaryon track,warningat risk,dangeroff track,successdone — and the badge next to it says the same. Every bar shows its value, so the label keeps one width and the tracks end on one line.Q4 goalsMove 40 customers to annual billingSalesOn track78%Cut invoice disputes below 2 %FinanceAt risk52%Ship the invoice editorProductDone100%Answer support within 4 hoursSupportOff track31%A total and its parts
sizesets the weight:lgfor the total,xsfor the parts under it. Inside a card the track’s own border is a second frame, soborderlessremoves it. In a stack of bars the values go to their own column — labels of different length would give every track a different width.StorageBusiness plan · deleted files are kept for 30 days38.2 of 50 GBInvoice PDFs21.4 GBAttachments11.2 GBBackups5.6 GBA line under the header while the size is unknown
The report does not know how long it will take, and
indeterminatepromises nothing: the bar runs and no value is announced. A thinxsline without a border sits on the header edge in a slot that keeps its height when idle, so the report does not jump. Under reduced motion the line becomes a still neutral fill.Revenue by channelUpdated 10:42Web store€30,060.00Mobile app€17,320.00Resellers€7,210.00
API generated from the package · cannot drift
Props
| Prop | Type | default | Description |
|---|---|---|---|
tone |
| "primary" | The colour tone of the fill. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | The thickness of the track. |
ariaLabel | string | undefined | undefined | The label for a screen reader (mandatory if there is no visible heading beside it). |
indeterminate | boolean | undefined | false | The progress is unknown: the bar runs, and no value is announced outside. |
borderless | boolean | undefined | undefined | Remove the border of the track: inside a card a second border is only noise. |
buffer | number | undefined | undefined | Loaded ahead: a layer behind the fill, `0..100`. Unset — there is no layer. |
showValue | boolean | undefined | false | Show the value as a label to the right of the track. |
formatValue | ((value: number) => string) | undefined | undefined | A format of your own for the value. It governs both the label and `aria-valuetext`. |
valuerequired | number | — | The current value `0..100`; values out of range are clamped, and a non-numeric one becomes `0`. |
Types
Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.
import type { GrProgressBarProps, GrProgressBarConfigurableProps, GrProgressBarTone } from '@feugene/granularity/components/GrProgressBar'Filedist/types/components/GrProgressBar/GrProgressBar.vue.d.ts
interface GrProgressBarProps {
value: number;
buffer?: number;
indeterminate?: boolean;
showValue?: boolean;
formatValue?: (value: number) => string;Filedist/types/components/GrProgressBar/config.d.ts
const grProgressBarConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrProgressBar">;Filedist/types/components/GrProgressBar/safelist.d.ts
const grProgressBarSafelist: string[];Filedist/types/components/GrProgressBar/defaults.d.ts
interface GrProgressBarConfigurableProps {
size: GrComponentSize;
borderless: boolean;
}Filedist/types/components/GrProgressBar/grStyle.d.ts
type GrProgressBarTone = GrTone;type GrProgressBarSize = GrComponentSize;Usage from the library prose
When the progress is unknown
<GrProgressBar :value="percent" :indeterminate="!sizeKnown" aria-label="Import" />indeterminate beats value: the bar runs, and aria-valuenow and aria-valuetext are not set
at all — by the specification that is exactly the sign of indeterminacy, and a separate
aria-busy is not needed. The label of the value is not rendered in this mode: there is nothing
to show.
This is the most frequent progress scenario — the request has left and the server did not report
the size of the answer. GrFileUpload switches the mode on itself when the XHR has no
lengthComputable.
Under prefers-reduced-motion: reduce the bar does not freeze but becomes a neutral fill across
the full width (--gr-progress-indeterminate-bg). A frozen frame of a running bar would lie at
the left edge and read as “40% progress”, that is, it would lie about the state; a fill across the
full width says “work is going on, the value is unknown” and pretends to be neither zero nor
completion. The period of a run is --gr-progress-indeterminate-duration. The general contract of
movement — motion.md.
The label of the value
<GrProgressBar :value="percent" show-value aria-label="Loading" />
<GrProgressBar :value="percent" :format-value="v => `${gb(v)} of 32 GB`" show-value />showValue prints whole percentages to the right of the track. The label is of a fixed width and
uses tabular figures: the move from 9% to 10% must not jerk the track.
formatValue governs both the label and aria-valuetext — “184 of 512 MB” instead of a bare
“36”. Without a format of your own aria-valuetext is not set: a screen reader already reads “36”
with aria-valuemax="100" as a percentage, and there is no point duplicating that with text. The
format works without showValue too — then it remains for the screen reader alone.
The buffer
<GrProgressBar :value="played" :buffer="buffered" aria-label="Playback" />A second layer behind the fill: played against buffered, filled against confirmed by the server.
It is clamped by the same rules as value (0..100, NaN → 0) and is not obliged to be larger
than the value — the layer will simply turn out shorter than the fill.
The buffer does not inherit tone and is coloured with a single --gr-progress-buffer-bg: not
all eight tones have -light roles, and a neutral layer between the track and the fill reads
well with any of them.
A value out of range
value and buffer are clamped to 0..100, and any non-numeric value turns into 0. A bar
given -5 or 140 does not break the layout and does not give away an invalid aria-valuenow —
that is a deliberate boundary rather than a side effect.
A mandatory value that did not arrive falls here as well: the bar is drawn empty,
aria-valuenow="0", and in dev mode the component prints a warning. Staying silent here is not
allowed — a screen reader reads aria-valuenow="NaN", and that is an axe violation.
Styling
size is xs…lg and is read from GrConfigProvider; for a linear bar that is the thickness of
the track and the type size of the label, while the width is set by the container. The tone of the
fill is tone from the palette of the package.
borderless removes the border of the track and is likewise read from GrConfigProvider. The
border is needed on a bare background, where the --gr-muted track is barely distinguishable from
the page; inside a card it becomes a second border next to its own.
Pointed customisation is done with the --gr-progress-bg variables (and one per tone),
--gr-progress-buffer-bg, --gr-progress-indeterminate-bg and
--gr-progress-indeterminate-duration. The full list — tokens.md.
The accessible name
role="progressbar" stands on the track, and ariaLabel is the only way to give the bar a name: a
neighbouring heading does not count as a name. Inside GrFileUpload the label is substituted by
the uploader itself.
Props in this example