packages/react-aria/docs/meter/useMeter.mdx
{/* 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/meter'; import {HeaderInfo, FunctionAPI, TypeContext, InterfaceType, PageDescription} from '@react-spectrum/docs'; import packageData from '@react-aria/meter/package.json'; import Anatomy from './anatomy.svg'; import {ExampleCard} from '@react-spectrum/docs/src/ExampleCard'; import circularPreview from 'url:./circular-example.png';
<PageDescription>{docs.exports.useMeter.description}</PageDescription>
<HeaderInfo packageData={packageData} componentNames={['useMeter']} sourceData={[ {type: 'W3C', url: 'https://www.w3.org/WAI/ARIA/apg/patterns/meter/'} ]} />
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.
meter via ARIA, with fallback to progressbar where unsupportedMeters 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:
<TypeContext.Provider value={docs.links}> <InterfaceType properties={docs.links[docs.exports.useMeter.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.
import {useMeter} from '@react-aria/meter';
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: 'lightgray'}}>
<div style={{width: barWidth, height: 10, background: 'green'}} />
</div>
</div>
);
}
<Meter
label="Storage space"
value={25} />
<ExampleCard url="https://codesandbox.io/s/lucid-jackson-xj8pok?file=/src/App.js" preview={circularPreview} title="Circular Gauge" description="A circular meter built with SVG." />
The following examples show how to use the Meter component created in the above example.
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.
<Meter
label="Widgets Used"
minValue={50}
maxValue={150}
value={100} />
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.
<Meter
label="Currency"
formatOptions={{style: 'currency', currency: 'JPY'}}
value={60} />
The valueLabel prop allows the formatted value to be replaced with a custom string.
<Meter
label="Space used"
valueLabel="54 of 60GB"
value={90} />
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.
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.