useMeter

Provides the accessibility implementation for a meter component. Meters represent a quantity within a known range, or a fractional value.

installyarn add @react-aria/meter
version3.1.3
usageimport {useMeter} from '@react-aria/meter'

API#


useMeter( (props: AriaMeterProps )): MeterAria

Features#


The <meter> HTML element can be used to build a meter, however it is very difficult to style cross browser. useMeter helps achieve accessible meters that can be styled as needed.

Meters are similar to progress bars, but represent a quantity as opposed to progress over time. See the useProgressBar hook for more details about progress bars.

  • Exposed to assistive technology as a meter via ARIA, with fallback to progressbar where unsupported
  • Labeling support for accessibility
  • Internationalized number formatting as a percentage or value

Anatomy#


Meter anatomy diagramValueLabelTasks completed4 of 5TrackFill

Meters consist of a track element showing the full value in a range, a fill element showing the current value, a label, and an optional value label. The track and bar elements represent the value visually, while a wrapper element represents the meter to assistive technology using the meter ARIA role.

useMeter returns two sets of props that you should spread onto the appropriate element:

NameTypeDescription
meterPropsHTMLAttributes<HTMLElement>Props for the meter container element.
labelPropsHTMLAttributes<HTMLElement>Props for the meter's visual label (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 Meter(props) {
  let {
    label,
    showValueLabel = !!label,
    value,
    minValue = 0,
    maxValue = 100
  } = props;
  let {meterProps, labelProps} = useMeter(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 {...meterProps} style={{width: 200}}>
      <div style={{display: 'flex', justifyContent: 'space-between'}}>
        {label && <span {...labelProps}>{label}</span>}
        {showValueLabel && <span>{meterProps['aria-valuetext']}</span>}
      </div>
      <div style={{height: 10, background: 'gray'}}>
        <div style={{width: barWidth, height: 10, background: 'green'}} />
      </div>
    </div>
  );
}

<Meter label="Storage space" value={250} maxValue={1000} />
function Meter(props) {
  let {
    label,
    showValueLabel = !!label,
    value,
    minValue = 0,
    maxValue = 100
  } = props;
  let {meterProps, labelProps} = useMeter(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 {...meterProps} style={{width: 200}}>
      <div
        style={{
          display: 'flex',
          justifyContent: 'space-between'
        }}>
        {label && <span {...labelProps}>{label}</span>}
        {showValueLabel && (
          <span>{meterProps['aria-valuetext']}</span>
        )}
      </div>
      <div style={{height: 10, background: 'gray'}}>
        <div
          style={{
            width: barWidth,
            height: 10,
            background: 'green'
          }}
        />
      </div>
    </div>
  );
}

<Meter
  label="Storage space"
  value={250}
  maxValue={1000}
/>
function Meter(props) {
  let {
    label,
    showValueLabel = !!label,
    value,
    minValue = 0,
    maxValue = 100
  } = props;
  let {
    meterProps,
    labelProps
  } = useMeter(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
      {...meterProps}
      style={{
        width: 200
      }}>
      <div
        style={{
          display:
            'flex',
          justifyContent:
            'space-between'
        }}>
        {label && (
          <span
            {...labelProps}>
            {label}
          </span>
        )}
        {showValueLabel && (
          <span>
            {
              meterProps[
                'aria-valuetext'
              ]
            }
          </span>
        )}
      </div>
      <div
        style={{
          height: 10,
          background:
            'gray'
        }}>
        <div
          style={{
            width: barWidth,
            height: 10,
            background:
              'green'
          }}
        />
      </div>
    </div>
  );
}

<Meter
  label="Storage space"
  value={250}
  maxValue={1000}
/>

Internationalization#


Value formatting#

useMeter will handle localized formatting of the value label for accessibility automatically. This is returned in the aria-valuetext prop in meterProps. 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 meter 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.