# Meter (/docs/meter)





## API Reference [#api-reference]

<BaseUIReference href="https://base-ui.com/react/components/meter" />

## Basic [#basic]

<Preview cssProperties="meterPlaygroundCssProperties">
  <MeterExample />

  <Preview.Code>
    {`
          import {
            Meter,
            MeterLabel,
            MeterValue,
          } from "moduix";

          export function MeterDemo() {
            return (
              <Meter value={24}>
                <MeterLabel>Storage Used</MeterLabel>
                <MeterValue />
              </Meter>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSSProperties>
    {(context) => <MeterCssPropertiesPanel {...context} />}
  </Preview.CSSProperties>

  <Preview.CSSPlayground>
    {(context) => <MeterCssPlaygroundPanel {...context} />}
  </Preview.CSSPlayground>
</Preview>

## Anatomy [#anatomy]

`Meter` combines a semantic root with visible value text and a visual fill track. In the default setup,
the track and indicator are rendered automatically, so most use cases only need `Meter`, `MeterLabel`,
and `MeterValue`.

```text
Meter[value]
├─ MeterLabel
├─ MeterValue
└─ MeterTrack
   └─ MeterIndicator
```

```tsx
<Meter value={64}>
  <MeterLabel>Storage used</MeterLabel>
  <MeterValue>{(formattedValue) => `${formattedValue} used`}</MeterValue>
</Meter>
```

| Part             | Role                                                                                               |
| ---------------- | -------------------------------------------------------------------------------------------------- |
| `Meter`          | Root state and accessibility layer. Provides `value`, `min`, `max`, formatting, and ARIA metadata. |
| `MeterLabel`     | Visible text label associated with the meter for users and assistive technology.                   |
| `MeterValue`     | Formatted value output. Can render default text or a custom function for value wording.            |
| `MeterTrack`     | Visual track slot behind the fill. Rendered automatically unless `withTrack={false}` is set.       |
| `MeterIndicator` | Fill slot that reflects current progress within the track.                                         |

`Meter` does not use service slots such as `portal`, `backdrop`, or `viewport`.
Keep the default track structure when possible, and customize slot-level visuals through `classNames`
or by composing `MeterTrack` and `MeterIndicator` manually when the design needs full control.

## Composition [#composition]

Use `withTrack={false}` and compose `MeterTrack` with `MeterIndicator` when the visual structure needs direct access to Base UI slots.

<Preview>
  <CompositionMeterExample />

  <Preview.Code>
    {`
          import {
            Meter,
            MeterIndicator,
            MeterLabel,
            MeterTrack,
            MeterValue,
          } from "moduix";

          export function CompositionMeterDemo() {
            return (
              <Meter value={58} withTrack={false} className={styles.composedMeter}>
                <MeterLabel>Team capacity</MeterLabel>
                <MeterValue>{(formattedValue) => \`\${formattedValue} available\`}</MeterValue>
                <MeterTrack className={styles.composedTrack}>
                  <MeterIndicator className={styles.composedIndicator} />
                </MeterTrack>
              </Meter>
            );
          }

      `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .composedMeter {
            --meter-width: 18rem;
            --meter-track-height: 0.625rem;
          }

          .composedTrack {
            box-sizing: border-box;
            display: flex;
            align-items: stretch;
            height: 1rem;
            border: var(--border-width-sm) solid transparent;
            border-radius: var(--radius-md);
            background:
              linear-gradient(var(--color-background), var(--color-background)) padding-box,
              linear-gradient(90deg, var(--color-chart-3), var(--color-primary)) border-box;
            box-shadow: none;
          }

          .composedIndicator {
            display: block;
            height: 100%;
            border-radius: calc(var(--radius-md) - var(--border-width-sm));
            background: linear-gradient(90deg, var(--color-chart-3), var(--color-primary));
          }

      `}
  </Preview.CSS>
</Preview>

## Examples [#examples]

### Min Max Range [#min-max-range]

Use `min` and `max` when the value belongs to a custom range instead of the default `0` to `100`.

<Preview>
  <MinMaxRangeMeterExample />

  <Preview.Code>
    {`
          import {
            Meter,
            MeterLabel,
            MeterValue,
          } from "moduix";

          export function MinMaxRangeMeterDemo() {
            return (
              <Meter value={420} min={200} max={800}>
                <MeterLabel>Requests per minute</MeterLabel>
                <MeterValue />
              </Meter>
            );
          }
        `}
  </Preview.Code>
</Preview>

### Controlled [#controlled]

Keep the value in React state when the meter mirrors another control or live application state.

<Preview>
  <ControlledMeterExample />

  <Preview.Code>
    {`
          import {
            Meter,
            MeterLabel,
            MeterValue,
          } from "moduix";
          import { useState } from "react";

          function ControlledMeter() {
            const [value, setValue] = useState(45);

            return (
              <div className={styles.stack}>
                <Meter value={value}>
                  <MeterLabel>Capacity</MeterLabel>
                  <MeterValue />
                </Meter>
                <input
                  className={styles.range}
                  type="range"
                  min={0}
                  max={100}
                  value={value}
                  onChange={(event) => {
                    setValue(Number(event.target.value));
                  }}
                />
              </div>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .stack {
            display: grid;
            gap: var(--spacing-4);
          }

          .range {
            width: 12rem;
          }
        `}
  </Preview.CSS>
</Preview>

### Percent Format [#percent-format]

Use `format` and a custom `MeterValue` child function to present the value in user-facing text.

<Preview>
  <PercentFormatMeterExample />

  <Preview.Code>
    {`
          import {
            Meter,
            MeterLabel,
            MeterValue,
          } from "moduix";

          export function PercentFormatMeterDemo() {
            return (
              <Meter value={0.64} min={0} max={1} format={{ style: "percent", maximumFractionDigits: 0 }}>
                <MeterLabel>Usage</MeterLabel>
                <MeterValue>{(formattedValue) => \`\${formattedValue} used\`}</MeterValue>
              </Meter>
            );
          }
        `}
  </Preview.Code>
</Preview>

### Custom Styles [#custom-styles]

`Meter` renders the track and indicator automatically. Use `className` for the root and `classNames` for the internal track or indicator slots.

<Preview>
  <CustomStylesMeterExample />

  <Preview.Code>
    {`
          import {
            Meter,
            MeterLabel,
            MeterValue,
          } from "moduix";

          export function CustomStylesMeterDemo() {
            return (
              <Meter
                value={72}
                className={styles.customMeter}
                classNames={{ track: styles.customTrack, indicator: styles.customIndicator }}
              >
                <MeterLabel>Monthly quota</MeterLabel>
                <MeterValue />
              </Meter>
            );
          }
        `}
  </Preview.Code>

  <Preview.CSS>
    {`
          .customMeter {
            --meter-width: 16rem;
            --meter-track-height: 0.75rem;
            --meter-track-bg: var(--color-accent);
          }

          .customTrack {
            box-shadow: inset 0 0 0 var(--border-width-md)
              color-mix(in oklab, var(--color-primary), transparent 75%);
          }

          .customIndicator {
            background: linear-gradient(90deg, var(--color-primary), var(--color-chart-2));
          }
        `}
  </Preview.CSS>
</Preview>
