Back to React Spectrum

useProgressBar

packages/react-aria/docs/progress/useProgressBar.mdx

2022-12-167.3 KB
Original Source

{/* Copyright 2020 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs'; export default Layout;

import docs from 'docs:@react-aria/progress'; import {HeaderInfo, FunctionAPI, TypeContext, InterfaceType, PageDescription} from '@react-spectrum/docs'; import packageData from '@react-aria/progress/package.json'; import Anatomy from './anatomy.svg';


category: Status keywords: [progressbar, aria]

useProgressBar

<PageDescription>{docs.exports.useProgressBar.description}</PageDescription>

<HeaderInfo packageData={packageData} componentNames={['useProgressBar']} sourceData={[ {type: 'W3C', url: 'https://www.w3.org/TR/wai-aria-1.2/#progressbar'} ]} />

API

<FunctionAPI function={docs.exports.useProgressBar} links={docs.links} />

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

<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:

<TypeContext.Provider value={docs.links}> <InterfaceType properties={docs.links[docs.exports.useProgressBar.return.id].properties} /> </TypeContext.Provider>

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

tsx
import {useProgressBar} from '@react-aria/progress';

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 = `${Math.round(percentage * 100)}%`;

  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: 'lightgray'}}>
        <div style={{width: barWidth, height: 10, background: 'orange'}} />
      </div>
    </div>
  );
}

<ProgressBar label="Loading…" value={80} />

Circular example

Progress bars may also be represented using a circular visualization rather than a line. This is often used to represent indeterminate operations, but may also be used for determinate progress indicators when space is limited. The following example shows a progress bar visualized as a circular spinner using SVG.

tsx
function ProgressCircle(props) {
  let {isIndeterminate, value, minValue = 0, maxValue = 100} = props;
  let {progressBarProps} = useProgressBar(props);

  let center = 16;
  let strokeWidth = 4;
  let r = 16 - strokeWidth;
  let c = 2 * r * Math.PI;
  let percentage = isIndeterminate ? 0.25 : (value - minValue) / (maxValue - minValue);
  let offset = c - percentage * 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} ${c}`}
        strokeDashoffset={offset}
        transform="rotate(-90 16 16)">
        {props.isIndeterminate &&
          <animateTransform
            attributeName="transform"
            type="rotate"
            begin="0s"
            dur="1s"
            from="0 16 16"
            to="360 16 16"
            repeatCount="indefinite" />
        }
      </circle>
    </svg>
  );
}

<ProgressCircle aria-label="Loading…" value={60} />

Usage

The following examples show how to use the ProgressBar and ProgressCircle components created in the above example.

Custom value scale

By default, the value prop represents the current percentage of progress, as the minimum and maximum values default to 0 and 100, respectively. Alternatively, a different scale can be used by setting the minValue and maxValue props.

tsx
<ProgressBar
  label="Loading…"
  minValue={50}
  maxValue={150}
  value={100} />

Value formatting

Values are formatted as a percentage by default, but this can be modified by using the formatOptions prop to specify a different format. formatOptions is compatible with the option parameter of Intl.NumberFormat and is applied based on the current locale.

tsx
<ProgressBar
  label="Sending…"
  formatOptions={{style: 'currency', currency: 'JPY'}}
  value={60} />

Custom value label

The valueLabel prop allows the formatted value to be replaced with a custom string.

tsx
<ProgressBar
  label="Feeding…"
  valueLabel="30 of 100 dogs"
  value={30} />

Indeterminate

The isIndeterminate prop can be used to represent an indeterminate operation. The ProgressCircle component created above implements an animation to indicate this visually.

tsx
<ProgressCircle
  aria-label="Loading…"
  isIndeterminate />

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.