useProgressBar
Provides the accessibility implementation for a progress bar component. Progress bars show either determinate or indeterminate progress of an operation over time.
install | yarn add @react-aria/progress |
---|---|
version | 3.1.3 |
usage | import {useProgressBar} from '@react-aria/progress' |
API#
useProgressBar(
(props: AriaProgressBarProps
)): ProgressBarAria
Features#
The <progress>
HTML element can be used to build a progress bar, however it is
very difficult to style cross browser. useProgressBar
helps achieve accessible
progress bars and spinners that can be styled as needed.
- Exposed to assistive technology as a progress bar via ARIA
- Labeling support for accessibility
- Internationalized number formatting as a percentage or value
- Determinate and indeterminate progress support
Anatomy#
Progress bars consist of a track element showing the full progress of an operation, a fill element showing the current progress, a label, and an optional value label. The track and bar elements represent the progress visually, while a wrapper element represents the progress to assistive technology using the progressbar ARIA role.
useProgressBar
returns two sets of props that you should spread onto the appropriate element:
Name | Type | Description |
progressBarProps | HTMLAttributes<HTMLElement> | Props for the progress bar container element. |
labelProps | HTMLAttributes<HTMLElement> | Props for the progress bar's visual label element (if any). |
If there is no visual label, an aria-label
or aria-labelledby
prop must be passed instead
to identify the element to screen readers.
Example#
function ProgressBar(props) {
let {
label
showValueLabel = !!label
value
minValue = 0
maxValue = 100
} = props;
let {progressBarProps labelProps} = useProgressBar(props);
// Calculate the width of the progress bar as a percentage
let percentage = (value - minValue) / (maxValue - minValue);
let barWidth = ` %`;
return (
<div ...progressBarProps style={width: 200}>
<div style={display: 'flex' justifyContent: 'space-between'}>
label && <span ...labelProps> label</span>
showValueLabel && <span> progressBarProps['aria-valuetext']</span>
</div>
<div style={height: 10 background: 'gray'}>
<div style={width: barWidth height: 10 background: 'orange'} />
</div>
</div>
);
}
<ProgressBar label="Loading..." value=30 />
function ProgressBar(props) {
let {
label
showValueLabel = !!label
value
minValue = 0
maxValue = 100
} = props;
let {progressBarProps labelProps} = useProgressBar(
props
);
// Calculate the width of the progress bar as a percentage
let percentage =
(value - minValue) / (maxValue - minValue);
let barWidth = ` %`;
return (
<div ...progressBarProps style={width: 200}>
<div
style={
display: 'flex'
justifyContent: 'space-between'
}>
label && <span ...labelProps> label</span>
showValueLabel && (
<span> progressBarProps['aria-valuetext']</span>
)
</div>
<div style={height: 10 background: 'gray'}>
<div
style={
width: barWidth
height: 10
background: 'orange'
}
/>
</div>
</div>
);
}
<ProgressBar label="Loading..." value=30 />
function ProgressBar(
props
) {
let {
label
showValueLabel = !!label
value
minValue = 0
maxValue = 100
} = props;
let {
progressBarProps
labelProps
} = useProgressBar(
props
);
// Calculate the width of the progress bar as a percentage
let percentage =
(value - minValue) /
(maxValue -
minValue);
let barWidth = ` %`;
return (
<div
...progressBarProps
style={
width: 200
}>
<div
style={
display:
'flex'
justifyContent:
'space-between'
}>
label && (
<span
...labelProps>
label
</span>
)
showValueLabel && (
<span>
progressBarProps[
'aria-valuetext'
]
</span>
)
</div>
<div
style={
height: 10
background:
'gray'
}>
<div
style={
width: barWidth
height: 10
background:
'orange'
}
/>
</div>
</div>
);
}
<ProgressBar
label="Loading..."
value=30
/>
Indeterminate#
Progress bars can represent an indeterminate operation. They may also be used to represent progress visually as a circle rather than as a line. The following example shows an indeterminate progress bar visualized as a circular spinner using SVG.
function Spinner() {
let {progressBarProps} = useProgressBar({
isIndeterminate: true
'aria-label': 'Loading...'
});
let center = 16;
let strokeWidth = 4;
let r = 16 - strokeWidth;
let c = 2 * r * MathPI;
let offset = c - (1 / 4) * c;
return (
<svg
...progressBarProps
width=32
height=32
viewBox="0 0 32 32"
fill="none"
strokeWidth= strokeWidth>
<circle role="presentation" cx= center cy= center r= r stroke="gray" />
<circle
role="presentation"
cx= center
cy= center
r= r
stroke="orange"
strokeDasharray= c
strokeDashoffset= offset>
<animateTransform
attributeName="transform"
type="rotate"
begin="0s"
dur="1s"
from="0 16 16"
to="360 16 16"
repeatCount="indefinite"
/>
</circle>
</svg>
);
}
function Spinner() {
let {progressBarProps} = useProgressBar({
isIndeterminate: true
'aria-label': 'Loading...'
});
let center = 16;
let strokeWidth = 4;
let r = 16 - strokeWidth;
let c = 2 * r * MathPI;
let offset = c - (1 / 4) * c;
return (
<svg
...progressBarProps
width=32
height=32
viewBox="0 0 32 32"
fill="none"
strokeWidth= strokeWidth>
<circle
role="presentation"
cx= center
cy= center
r= r
stroke="gray"
/>
<circle
role="presentation"
cx= center
cy= center
r= r
stroke="orange"
strokeDasharray= c
strokeDashoffset= offset>
<animateTransform
attributeName="transform"
type="rotate"
begin="0s"
dur="1s"
from="0 16 16"
to="360 16 16"
repeatCount="indefinite"
/>
</circle>
</svg>
);
}
function Spinner() {
let {
progressBarProps
} = useProgressBar({
isIndeterminate: true
'aria-label':
'Loading...'
});
let center = 16;
let strokeWidth = 4;
let r =
16 - strokeWidth;
let c =
2 * r * MathPI;
let offset =
c - (1 / 4) * c;
return (
<svg
...progressBarProps
width=32
height=32
viewBox="0 0 32 32"
fill="none"
strokeWidth=
strokeWidth
>
<circle
role="presentation"
cx= center
cy= center
r= r
stroke="gray"
/>
<circle
role="presentation"
cx= center
cy= center
r= r
stroke="orange"
strokeDasharray=
c
strokeDashoffset=
offset
>
<animateTransform
attributeName="transform"
type="rotate"
begin="0s"
dur="1s"
from="0 16 16"
to="360 16 16"
repeatCount="indefinite"
/>
</circle>
</svg>
);
}
Internationalization#
Value formatting#
useProgressBar
will handle localized formatting of the value label for accessibility
automatically. This is returned in the aria-valuetext
prop in progressBarProps
. You
can use this to create a visible label if needed and ensure that it is formatted correctly.
The number formatting can also be controlled using the formatOptions
prop.
RTL#
In right-to-left languages, the progress bar should be mirrored. The label is right-aligned, the value is left-aligned, and the fill progresses from right to left. Ensure that your CSS accounts for this.