# Composition (/docs/composition)

A microchart is built to sit inside an interface rather than in a chart pane of its own. This page has the placement
recipe for each context the gallery demos use: the size, the props, and the surface each one wants, plus how to compare
several charts at once.

## In a sentence

A chart in running prose scales with the surrounding **font** and sits on the text baseline. Wrap it in `mc-inline`
(shipped in `styles.css`) and pass `dots="none"` to drop its endpoint dots so it reads as one glyph. No chart in the
catalog draws an axis, so there is nothing else to turn off. Pass `summary={false}` as well, so a screen reader hears
the sentence and not a second description of it.

```tsx
<p>
    p95 latency this week{" "}
    <span className="mc-inline">
      <Sparkline data={latency} dots="none" summary={false} width={64} height={16} />
    </span>{" "}
    — trending down.
  </p>
```

See [Sizing](/docs/sizing#inline-in-a-sentence) for the `em`-based variant that scales with the surrounding type size.

## In a table cell

In a dense table the row already carries a name and a number, so the chart shows the _shape_ between them. Keep it
small, turn dots off, pass `summary={false}`, and leave the numeric column on `tabular-nums` so the figures line up.

```tsx
<tr>
    <td>checkout-api</td>
    <td><Sparkline data={latency} dots="none" summary={false} width={64} height={18} /></td>
    <td className="tabular-nums">31 ms</td>
  </tr>
```

## In a KPI card

The number leads and the chart gives it context. Give the chart a little more height, turn `fill` on so it reads as an
area, and pass `summary={false}`: the figure and its label already name the value.

```tsx
<div className="kpi">
    <span className="figure">1,600</span>
    <span className="unit">concurrent, now</span>
    <Sparkline data={connections} fill summary={false} width={120} height={32} />
  </div>
```

## In a tab or button

A spark beside a tab label previews what's behind it. The label is the primary read, so the chart goes _tiny_: a small
box with no dots.

```tsx
<button className="tab">
    CPU <Sparkline data={cpu} dots="none" summary={false} width={40} height={14} />
  </button>
```

## Charts sit on your surface

Every chart is transparent and **never paints its own background**. It takes its ink color from `--mc-stroke`, which
tracks light and dark for you, and shows through to whatever surface it lands on. The contrast of that surface is your
decision.

- Put the chart on a surface with enough contrast for a 1.5 px line. The data, valence, and accent inks all clear 4.5:1
  on the built-in light and dark themes. (`--mc-neutral`, the muted context ink for baselines and ghost marks, sits at
  3.5:1, past the 3:1 bar for non-text and quieter than the data.)
- A low-contrast tint stays low-contrast: the chart does not compensate for it.
- Need the ink to differ from the page (charts on a colored panel, frosted glass)? Set `--mc-stroke`, and the valence
  tokens if needed, on the container. See [Theming](/docs/theming#frosted-or-translucent-surfaces). Don't override
  `.mc-root` paint rules.

> The gallery renders each demo inside a panel with a card background and a hairline border. That panel is not part of the library; it's a surface, like your app's cards, table rows, and headers.

## Small multiples: one shared scale

When you place several sparklines in a row to _compare_ them, they must share one vertical scale. Auto-scaling each
chart to its own range makes a flat line and a spiking one look identical, which is a correctness bug and easy to miss.

`SparkGroup` handles it for you. It reads every child's `data`, computes **one** domain across all of them, and applies
**one** physical size, so the row is comparable. It's hook-free and RSC-safe, and a child's own explicit
`domain`/`width` still wins.

```tsx
import { SparkGroup } from "@microcharts/react";
import { Sparkline } from "@microcharts/react/sparkline";

<SparkGroup width={80} height={22}>
    <Sparkline data={us} summary={false} />
    <Sparkline data={eu} summary={false} />
    <Sparkline data={apac} summary={false} />
  </SparkGroup>
```

Pass `zero` when the group is bars or areas (so the shared domain anchors at zero), or an explicit `domain={[min, max]}`
when you want a fixed frame instead of the data's own range (`domain` defaults to `"shared"`).

Two more details. Only children that carry a `data` prop get the scale and size injected; plain wrappers, labels, and
captions pass through untouched, so you can interleave them without them picking up stray DOM attributes. The group
renders one `<div className="mc-group">`, an `inline-flex` row that wraps: its gap is `--mc-gap` scaled by
`--mc-density`, and `className`/`style` on `SparkGroup` land on that div if you want a different layout.

## The `summary` decision

Nearly every demo above passes `summary={false}`. Here is when that's the right call:

- **Standalone chart** (the one thing in its region): keep the auto-summary on. It's the accessible name a screen reader
  announces, generated from the data.
- **Repeated or captioned chart** (table rows, tabs, a chart next to a number that already states it): pass
  `summary={false}` to mark it decorative. The surrounding text is the accessible name, and a per-chart summary would
  make a screen reader read the same thing on every row.

`summary` is the only accessibility lever you set by hand. The `role="img"`, the `<title>`, and the interaction contract
on interactive entries (roving arrow keys, select-to-pin with **Enter** or **Space**, touch scrub, live announcements)
are automatic. See [Accessibility](/docs/accessibility).
