# FigureBand

A row of counted facts, divided by hairlines and nothing else.

- Group: Display
- Import: `import { FigureBand } from '@misoto22/folio'`
- Page: https://ui.misoto22.com/components/figure-band/
- Related: table

## Anatomy

- **Query wrapper** (required) — A plain <div> around the list, and it has to be: a container query resolves against an ANCESTOR container, never against the element declaring one. Its w-full is load-bearing too — contain: inline-size computes width without looking at the contents, so as a shrink-to-fit flex item it resolved to zero and the band rendered as two 0px columns.
- **Band** (required) — The <dl>: ruled top and bottom in --rule, two columns until the wrapper reaches @3xl and four after — a decision about how wide THIS band is, not how wide the window is.
- **Cell** (required) — One <div> per figure. Each divider width names the cells that do NOT open a row rather than adding a rule and taking it back, so no edge is ever painted past the last column.
- **Label** (required) — The <dt>: the mono uppercase kicker over the value.
- **Value** (required) — The <dd>, set in the heading face at --fs-lead or --fs-sub depending on scale.
- **Note** — A second <dd> under the same term — a trend, a qualifier, a second fact.

## Best practices

### Do

- Give it two or four figures. The grid is two columns until @3xl and four after, so three leaves a hole in both arrangements and five leaves three holes once the band goes four across.
- Use scale="sub" for a band that supports the page rather than being it: --fs-lead is the band-heading step, so a supporting figure set at lead is competing with the page’s own subject.
- Key each figure by the fact it counts — id is required rather than optional, because it is the React key and an index puts the next render’s number under the previous label as soon as the list reorders.

### Don’t

- Do not put a sentence in note. The value and the note are two <dd>s under one <dt>, so a screen reader reads them as two values of the same term: “Posts: 48, +6 this year” works, a clause does not.
- Do not set the column count with a viewport breakpoint through className. The band reads a container query, so a sm:grid-cols-4 written on it is wrong in a 390px sidebar of a 1440px window — which is the arrangement this replaced.
- figures={[]} renders null, so a band fed a filtered-empty array leaves no rules behind and no zero state either — if the absence is the news, the call site has to say so.

## Accessibility

- A <dl>: each cell is a term and its value, which a grid of divs cannot express.

## FigureBand

A framed, responsive group of related facts with semantic term/value pairs.

### Props

- `figures` (required) — `Figure[]`.
- `scale` — `'lead' | 'sub'` default `'lead'`. How large the value is set. `lead` is for a band that is the point of its page — a stats headline, where the numbers ARE the content. `sub` is for a band that supports the page around it, and keeps the ladder honest: a supporting figure must not be set at the same size as the page's own subject.
- `label` — `string`. Names the band for assistive tech when it has no visible heading of its own.

Also accepts: `Omit<HTMLAttributes<HTMLDListElement>, 'children'>`.

## Example — default

```tsx
import { FigureBand } from '@misoto22/folio'

<FigureBand
  label="Deploys, last 30 days"
  figures={[
    { id: 'releases', label: 'Releases', value: '12' },
    { id: 'duration', label: 'Median build', value: '2m 14s', note: 'down from 3m 40s' },
    { id: 'rollbacks', label: 'Rollbacks', value: '0' },
    { id: 'uptime', label: 'Uptime', value: '99.98%', note: 'measured at the edge' },
  ]}
/>
```

## Example — a supporting band

```tsx
import { FigureBand, Heading, Text } from '@misoto22/folio'

<div className="flex w-full flex-col gap-5">
  <Heading level={3}>Retrieval rewrite</Heading>
  <Text size="sm">
    Chunking moved from a fixed window to headings, and the citation panel
    started reading the same rows the answer did.
  </Text>
  <FigureBand
    scale="sub"
    label="Retrieval, before and after"
    figures={[
      { id: 'latency', label: 'Median latency', value: '240ms', note: 'from 610ms' },
      { id: 'recall', label: 'Answers with a citation', value: '96%', note: 'from 71%' },
    ]}
  />
</div>
```

## Example — a note is a second value

```tsx
import { FigureBand } from '@misoto22/folio'

<FigureBand
  label="The site, at a glance"
  figures={[
    { id: 'posts', label: 'Posts', value: '48', note: '+6 this year' },
    { id: 'frames', label: 'Frames', value: '1,204', note: '38 rolls' },
    { id: 'projects', label: 'Projects', value: '11', note: '3 shipped' },
    { id: 'words', label: 'Words', value: '86k', note: 'English and Chinese' },
  ]}
/>
```

## Example — in a narrow column

```tsx
import { FigureBand } from '@misoto22/folio'

<div className="w-full max-w-96 rounded-(--radius-lg) border border-(--rule) p-4">
  <FigureBand
    scale="sub"
    label="This release"
    figures={[
      { id: 'components', label: 'Components', value: '61' },
      { id: 'tokens', label: 'Tokens', value: '145' },
      { id: 'examples', label: 'Examples', value: '147' },
      { id: 'size', label: 'Peer deps', value: '2' },
    ]}
  />
</div>
```
