# Capacity meter

A row of two to four short bars, as many filled as places are taken, with the same in words, such as "1 of 2 places".

Block: `smbk-capacity-meter`. Status: experimental. Figma: the Figma file, https://www.figma.com/community/file/1688324308358870630. Desktop and mobile: differ by presentation only.

## Options

| Axis | Values | Default | Meaning |
|---|---|---|---|

Parts: `smbk-capacity-meter__segments`, `smbk-capacity-meter__segment`, `smbk-capacity-meter__words`

## Markup

```html
<div
  aria-label="Agents on the website"
  class="smbk-capacity-meter"
  role="meter"
  aria-valuemin="0"
  aria-valuemax="2"
  aria-valuenow="1"
  aria-valuetext="1 of 2 places"
>
  <span class="smbk-capacity-meter__segments" aria-hidden="true">
    <span class="smbk-capacity-meter__segment smbk-capacity-meter__segment--filled"></span>
    <span class="smbk-capacity-meter__segment"></span>
  </span>
  <span class="smbk-capacity-meter__words" aria-hidden="true">1 of 2 places</span>
</div>
```

## React

```tsx
import { CapacityMeter } from './design-system/components/capacity-meter/capacity-meter.js';

<CapacityMeter filled={1} segments={2} aria-label="Agents on the website" />
```

## Stylesheet

```css
/* smbk-capacity-meter — Capacity meter. Figma "Capacity meter" 7118:653 (Segments × Filled, 12 variants).
 * How many of a few places are taken: a row of short bars, as many filled as are used, then the same in
 * words ("1 of 2 places"). The filled bars are the inverse surface, the empty ones the track; the meaning
 * is in the words, so the bars are never the only sign. */

.smbk-capacity-meter {
  display: inline-flex;
  align-items: center;
  gap: var(--smbk-space-inline-md);
  vertical-align: middle;
}

.smbk-capacity-meter__segments {
  display: inline-flex;
  flex-shrink: 0;
  gap: var(--smbk-space-inline-xs);
}

.smbk-capacity-meter__segment {
  display: block;
  width: var(--smbk-size-20);
  height: var(--smbk-size-8);
  border-radius: var(--smbk-radius-full);
  background: var(--smbk-color-surface-track);
}

.smbk-capacity-meter__segment--filled {
  background: var(--smbk-color-surface-inverse);
}

/* Figures of one width, so the words do not shift sideways as a place is taken or freed. */
.smbk-capacity-meter__words {
  color: var(--smbk-color-text-subtle);
  font-family: var(--smbk-typography-body-sm-font-family);
  font-size: var(--smbk-typography-body-sm-font-size);
  font-weight: var(--smbk-typography-body-sm-font-weight);
  line-height: var(--smbk-typography-body-sm-line-height);
  letter-spacing: var(--smbk-typography-body-sm-letter-spacing);
  font-variant-numeric: tabular-nums;
}

/* ---- high contrast (forced colors) ---- */
/* In Windows high-contrast mode the browser drops fills; each bar is outlined in the text color and the
   filled ones are filled with it, so taken and free places still differ. */

@media (forced-colors: active) {
  .smbk-capacity-meter__segment {
    outline: var(--smbk-border-width-hairline) solid CanvasText;
    outline-offset: calc(-1 * var(--smbk-border-width-hairline));
  }

  .smbk-capacity-meter__segment--filled {
    background: CanvasText;
  }
}
```

## Tokens it reads

```json
{
  "space": {
    "inline": {
      "md": {
        "$type": "dimension",
        "$value": "{{space.8}}",
        "$description": "Gap between things side by side, medium."
      },
      "xs": {
        "$type": "dimension",
        "$value": "{{space.4}}",
        "$description": "Gap between things side by side, extra small."
      }
    }
  },
  "size": {
    "8": {
      "$type": "dimension",
      "$value": "8px",
      "$description": "Raw size step, 8 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    },
    "20": {
      "$type": "dimension",
      "$value": "20px",
      "$description": "Raw size step, 20 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    }
  },
  "radius": {
    "full": {
      "$type": "dimension",
      "$value": "{{radius.9999}}",
      "$description": "Capsule: pills, chips, switches."
    }
  },
  "color": {
    "surface": {
      "track": {
        "$type": "color",
        "$value": "{{color.grey.500}}",
        "$description": "The filled track of a switch that is off: 3:1 against the page so the switch shows where it is (decision C)."
      },
      "inverse": {
        "$type": "color",
        "$value": "{{color.grey.850}}",
        "$description": "The opposite surface: tooltips, dark chips."
      }
    },
    "text": {
      "subtle": {
        "$type": "color",
        "$value": "{{color.grey.700}}",
        "$description": "Secondary text: descriptions, metadata."
      }
    }
  },
  "typography": {
    "body-sm": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "14px",
        "fontWeight": 400,
        "lineHeight": 1.5,
        "letterSpacing": "0px"
      }
    }
  },
  "border-width": {
    "hairline": {
      "$type": "dimension",
      "$value": "{{border-width.1}}",
      "$description": "Thin lines: dividers and almost every edge."
    }
  }
}
```

## Purpose

Shows how many of a few places are taken: how many agents are working on a project out of the two it allows, how many seats on a plan are in use. A row of short bars, one per place, as many filled as are taken, then the same in words, such as "1 of 2 places".

## Anatomy

- The block: the bars, then the words, side by side.
- The segments part, the row of bars.
- The segment part, one bar per place: the track color while free, the inverse surface once taken.
- The words part, the count in a small body style and the subtle text color: "1 of 2 places", or words of your own.

## When to use

- For a small, fixed number of places, two to four, where a reader wants to see at a glance whether there is room.
- In the head of a board column, under its title.

## When not to use

- For a large number, or a share of a total such as storage. Use a [meter](meter.md).
- For how far along a task is. Use a [progress bar](progress.md).
- For a count with no limit. Use a [badge](badge.md) or plain text.

## Behavior

The number of places is never below one, and the places taken are kept between none and all of them. The words are built from the two numbers and the word for what is counted, places by default; words of your own replace them.

## Accessibility

### What it does for you

- The whole is one meter. A screen reader hears its name and the words as its value, such as "Agents on the blog, meter, 1 of 2 places".
- The words say what the bars show, so the color of the bars is never the only sign.
- In high-contrast mode each bar is outlined and the taken ones are filled with the text color.

### What you must do

- Give it a name: `aria-label`, or `aria-labelledby` pointing at the heading it sits under.
- Make words of your own say the count, since they are also the value a screen reader hears.

### How to test

- With a screen reader, the meter is read by its name and its words as the value, such as "1 of 2 places".
- Tab past it: the meter takes no focus.
- In a forced-color mode, the bars are outlined and the taken ones filled.
- With text at 200% and the page 320 pixels wide, the words wrap and stay whole.

## Usage rules

### Do

- Name it for what it counts and where.
- Keep it to two, three or four places.

### Don't

- Use it for more places than can be counted at a glance.
- Write words that leave out the count.
