Skip to content

Meter

Reports a measurement inside a known range, like disk usage or a score.

View source View as Markdown

Meter reports where a measurement sits inside a range that is known up front: disk usage, a password score, how much of a budget is left. Useful whenever the number is a level rather than the state of a task; for something that starts, runs and finishes, use Progress.

Storage75%

384 GB of 512 GB, 75% full

App.vue
<template>
  <div class="flex w-64 flex-col gap-5">
    <Meter.Root
      v-slot="{ percentage }"
      :value="used"
      :options="{ max: total }"
      class="flex flex-col gap-2"
    >
      <div
        class="type-surface-code text-surface-muted flex items-baseline justify-between"
      >
        <Meter.Label>Storage</Meter.Label>
        <Meter.Value class="tabular-nums" />
      </div>

      <Meter.Track :class="track">
        <Meter.Indicator :class="indicator" />
      </Meter.Track>

      <p class="type-surface-caption text-surface-muted tabular-nums">
        {{ used }} GB of {{ total }} GB, {{ Math.round(percentage) }}% full
      </p>
    </Meter.Root>

    <div class="flex gap-2">
      <Button :class="button" @click="step(-64)">Free 64 GB</Button>
      <Button :class="button" @click="step(64)">Add 64 GB</Button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { Button } from '@maas/mirror/vue/Button'
import { Meter } from '@maas/mirror/vue/Meter'

const total = 512
const used = ref(384)

function step(amount: number) {
  used.value = Math.min(total, Math.max(0, used.value + amount))
}

const track = 'rounded-component-round bg-primary-subtle h-2.5 overflow-hidden'

const indicator = [
  'bg-primary-solid h-full',
  'transition-all duration-300 ease-linear',
].join(' ')

const button = [
  'rounded-component-md border-surface border px-2.5 py-1',
  'type-component-xs text-surface-muted hover:text-surface',
  'transition-all duration-100 ease-linear',
  'outline-4 outline-transparent focus-visible:focus-ring',
].join(' ')
</script>

Usage guidelines

  • A meter has no implicit name, so render a Meter.Label or give the root an aria-label. The label part wires aria-labelledby for you.must
  • The value is always a number, so leave the meter unrendered until there is something to report.should
  • Only the percentage and the formatted string are clamped, and aria-valuenow reports the clamped value, so clamp before you pass it in where the source can overshoot.should
  • options.format resolves against the runtime locale unless you pin one with options.locale. If the server and the client can differ, pass both, or fix the digits with minimumFractionDigits and maximumFractionDigits.should