# Chip group

Small plates you press on and off, laid in a tray that wraps: the filters over a table, the topics on a form, the sizes on a product. Each chip is a native checkbox, or a radio when only one may be down, drawn as a small cap that sinks below the tray with its lamp lit. A limit may be set on how many go down at once.

Kit part · Free · https://tactileui.dev/parts/chip-group

- Element: `<tui-chip-group class="tui-seg tui-chip-group">`
- Needs: `kit.css` and `kit.mjs` ([how to install the kit](https://tactileui.dev/docs/installation#the-kit))
- Categories: Badges & tags, Toggles & switches
- Finishes: Aluminium, Graphite, Oak, Walnut, Porcelain, Black, Daylight, Night, Paper, Phosphor, E-paper, AMOLED
- Volumes: Tactile, Quiet

## Variants

### Any number · checkboxes

```html
<div class="tui-seg tui-chip-group" role="group" aria-label="Run state"><label><input type="checkbox" name="cg2" value="passed" checked tabindex="-1"><span>Passed <small>12</small></span></label><label><input type="checkbox" name="cg2" value="failed" checked tabindex="-1"><span>Failed <small>4</small></span></label><label><input type="checkbox" name="cg2" value="slow" tabindex="-1"><span>Slow <small>3</small></span></label><label><input type="checkbox" name="cg2" value="cancelled" tabindex="-1"><span>Cancelled <small>1</small></span></label></div>
```

### One of several · radios

```html
<div class="tui-seg tui-chip-group" role="radiogroup" aria-label="Range"><label><input type="radio" name="cg3" value="today" checked tabindex="-1"><span>Today</span></label><label><input type="radio" name="cg3" value="7-days" tabindex="-1"><span>7 days</span></label><label><input type="radio" name="cg3" value="30-days" tabindex="-1"><span>30 days</span></label></div>
```

### No lamps · .tui-seg--plain

```html
<div class="tui-seg tui-chip-group tui-seg--plain" role="group" aria-label="Size"><label><input type="checkbox" name="cg4" value="small" checked tabindex="-1"><span>Small</span></label><label><input type="checkbox" name="cg4" value="medium" tabindex="-1"><span>Medium</span></label><label><input type="checkbox" name="cg4" value="large" tabindex="-1"><span>Large</span></label><label><input type="checkbox" name="cg4" value="extra-large" tabindex="-1"><span>Extra large</span></label></div>
```

### Small · .tui-chip-group--sm

```html
<div class="tui-seg tui-chip-group tui-chip-group--sm" role="group" aria-label="Run state"><label><input type="checkbox" name="cg5" value="passed" checked tabindex="-1"><span>Passed <small>12</small></span></label><label><input type="checkbox" name="cg5" value="failed" checked tabindex="-1"><span>Failed <small>4</small></span></label><label><input type="checkbox" name="cg5" value="slow" tabindex="-1"><span>Slow <small>3</small></span></label><label><input type="checkbox" name="cg5" value="cancelled" tabindex="-1"><span>Cancelled <small>1</small></span></label></div>
```

### Many chips wrap

```html
<div style="width:min(300px,100%)"><div class="tui-seg tui-chip-group" role="group" aria-label="Topics"><label><input type="checkbox" name="cg6" value="billing" tabindex="-1"><span>Billing</span></label><label><input type="checkbox" name="cg6" value="ledger" checked tabindex="-1"><span>Ledger</span></label><label><input type="checkbox" name="cg6" value="payments" tabindex="-1"><span>Payments</span></label><label><input type="checkbox" name="cg6" value="refunds" tabindex="-1"><span>Refunds</span></label><label><input type="checkbox" name="cg6" value="invoices" checked tabindex="-1"><span>Invoices</span></label><label><input type="checkbox" name="cg6" value="tax" tabindex="-1"><span>Tax</span></label><label><input type="checkbox" name="cg6" value="payouts" tabindex="-1"><span>Payouts</span></label><label><input type="checkbox" name="cg6" value="disputes" tabindex="-1"><span>Disputes</span></label><label><input type="checkbox" name="cg6" value="reports" tabindex="-1"><span>Reports</span></label></div></div>
```

### At the limit of three

```html
<div class="tui-seg tui-chip-group" role="group" aria-label="Run state"><label><input type="checkbox" name="cg7" value="failed" checked tabindex="-1"><span>Failed</span></label><label><input type="checkbox" name="cg7" value="slow" checked tabindex="-1"><span>Slow</span></label><label><input type="checkbox" name="cg7" value="queued" checked tabindex="-1"><span>Queued</span></label><label aria-disabled="true"><input type="checkbox" name="cg7" value="flaky" tabindex="-1" aria-disabled="true"><span>Flaky</span></label><label aria-disabled="true"><input type="checkbox" name="cg7" value="cancelled" tabindex="-1" aria-disabled="true"><span>Cancelled</span></label></div>
```

### Disabled

```html
<div class="tui-seg tui-chip-group" role="group" aria-label="Run state"><label aria-disabled="true"><input type="checkbox" name="cg8" value="failed" checked tabindex="-1" disabled><span>Failed</span></label><label aria-disabled="true"><input type="checkbox" name="cg8" value="slow" tabindex="-1" disabled><span>Slow</span></label></div>
```

## Every state

- Up
- Hover
- Pressing
- Down
- Focus
- At the limit
- Disabled

Hover, pressed and focus are forced with `.is-hover`, `.is-down` and `.is-focus`; checked and disabled are real.

## API

| Name | Kind | Values | What it does |
| - | - | - | - |
|  | element | role="group" and an aria-label | The tray, around labels that each hold a checkbox and a span. For one of several, use a div with role="radiogroup" and radios of one name. |
| label > input + span | element | checkbox or radio | One chip. The input is the real control and posts with the form; the span is the cap. Put a count in a small after the words. |
| max | attribute | on the group, a number | How many may be down at once. At the limit the rest are marked aria-disabled and a press changes nothing; a chip that is down can always be let go. |
| --plain · --sm | modifier | tui-seg--plain, tui-chip-group--sm | No lamp on the chips; a smaller tray of smaller chips. |
| value | property | string[] | The values that are down, in order. |
| tui-toggle-change | event | detail { value, values } | Bubbles from the group after a chip changes. The checkbox’s own change fires as ever. |
| chipSays({ count, max, refused }) | function | pure | The words the status line says: “2 of 3 chosen”, or why a press did nothing. |
| ← → · Home · End | key | with checkboxes | Move along the chips with one tab stop; Space latches the chip in focus. |

## Markup

```html
<!-- Any number down, up to a limit: checkboxes. They post with the form. -->
<tui-chip-group class="tui-seg tui-chip-group" role="group" aria-label="Filter runs by state" max="3">
  <label><input type="checkbox" name="state" value="failed" checked><span>Failed <small>4</small></span></label>
  <label><input type="checkbox" name="state" value="slow"><span>Slow <small>3</small></span></label>
  <label><input type="checkbox" name="state" value="queued"><span>Queued <small>2</small></span></label>
</tui-chip-group>

<!-- One of several: radios with one name. The arrows are the browser's own. -->
<div class="tui-seg tui-chip-group" role="radiogroup" aria-label="Range">
  <label><input type="radio" name="range" value="day"><span>Today</span></label>
  <label><input type="radio" name="range" value="week" checked><span>7 days</span></label>
</div>
```

```js
import { chipSays } from '/kit/kit.mjs';

const group = document.querySelector('tui-chip-group');
group.addEventListener('tui-toggle-change', (e) => {
  list.filter(e.detail.values);              // the values that are down, in order
});

group.value;                                  // ['failed', 'slow']
chipSays({ count: 2, max: 3 });               // '2 of 3 chosen'
```

The demo on the page:

```html
<div class="tui-panel" style="width:min(100%,460px);display:grid;gap:16px;text-align:left"><div class="tui-panel__head" style="margin-bottom:0"><span class="tui-label">Runs · Northwind CI</span><span class="tui-status"><span class="tui-lamp" data-on></span>Live</span></div>
  <div style="display:grid;gap:8px"><span class="tui-label" id="cg-l1">State · up to three</span>
    <tui-chip-group class="tui-seg tui-chip-group" role="group" aria-labelledby="cg-l1" max="3" data-cg="state"><label><input type="checkbox" name="state" value="passed" checked><span>Passed <small>12</small></span></label><label><input type="checkbox" name="state" value="failed" checked><span>Failed <small>4</small></span></label><label><input type="checkbox" name="state" value="slow"><span>Slow <small>3</small></span></label><label><input type="checkbox" name="state" value="cancelled"><span>Cancelled <small>1</small></span></label><label><input type="checkbox" name="state" value="queued"><span>Queued <small>2</small></span></label><label><input type="checkbox" name="state" value="flaky"><span>Flaky <small>2</small></span></label></tui-chip-group></div>
  <div style="display:grid;gap:8px"><span class="tui-label" id="cg-l2">Range</span>
    <div class="tui-seg tui-chip-group" role="radiogroup" aria-labelledby="cg-l2" data-cg="range"><label><input type="radio" name="range" value="today"><span>Today</span></label><label><input type="radio" name="range" value="7-days" checked><span>7 days</span></label><label><input type="radio" name="range" value="30-days"><span>30 days</span></label></div></div>
  <output class="tui-muted" style="font-size:var(--tui-t-small)" data-cg-out aria-live="polite">Showing Passed and Failed, in the last 7 days</output></div>
```

## Usage notes

Press Failed and Slow: each chip sinks and lights, and the line under the chips says what the list is showing. Three is the limit for the first group, so once three are down the rest stand still until you let one go. The second group is one of three: arrows move and choose.

## Accessibility

- Each chip is a native checkbox or radio, so a screen reader says “Failed, checkbox, not checked” with the group’s name, and a group of radios gets the browser’s own arrow keys and “1 of 3”.
- A chip that is down is also a chip that sits lower, with its lamp lit, so colour is never the only sign. A count is part of the chip’s name: “Failed 4”.
- With a limit, the chips that cannot go down are `aria-disabled`, still reachable by arrow, and a press says why in a polite line: “The limit is 3. Let one go to choose another.”
- Checkbox chips are one tab stop (a roving tabindex) with arrows, Home and End, and the chip the focus left is where it comes back to. Without the script every chip is a tab stop of its own.
- On a phone each chip is 44px tall and at least 44px wide, the tray wraps instead of scrolling sideways, and the press is not slowed by reduced motion.

## How it’s built

The segmented control already draws a cap that sinks below its tray and lights a lamp, in every finish and both volumes, so the chip is that cap: only the tray changes, which now wraps, leaves a little air between the chips and carries a count. The toggle group’s script supplies the single tab stop and the arrows, and the chip group adds one thing to it, a limit. Everything else is the input the browser already gave you.

## Rules

Filter or pick a few things with chips that latch: real checkboxes that post with a form, a limit if you want one, and one tab stop with arrows.

The full rules are in `chip-group.rules.md` in the brain, which ships with the Kit.

## Related parts

- [Toggle group](https://tactileui.dev/parts/toggle-group): The segmented control’s keys, each latching on its own, so any number can be down at once: bold and italic, the columns a table shows, the filters on a log. Every key is a checkbox and posts with the form. A lone toggle is a group of one, and a parting line splits clusters of keys in one slot.
- [Segmented control](https://tactileui.dev/parts/segmented): A row of keys in a tray with one pressed down: pick a view, a range or a mode and it applies at once. It is the kit’s selector without the lamps, with sizes, a full-width row and icon segments.
- [Tag](https://tactileui.dev/parts/tag): A small printed plate: a type, a count, a badge. Solid for the one tag that must stand out.
- [Check](https://tactileui.dev/parts/check): An option in a form: a small square key that presses below the plate when chosen, with a tick printed on it.
