# Toggle key

One key that latches below the plate and stays there. It is the kit’s own key with one state to keep, down or up, so it is the way to say mute, pin, bold or armed without the weight of a switch. A lamp in the cap may light while it is down.

Kit part · Free · https://tactileui.dev/parts/toggle-key

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

## Variants

### Words with a lamp

```html
<div style="display:flex;gap:10px;flex-wrap:wrap"><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="true"><span class="tui-lamp" data-lamp="amber" aria-hidden="true"></span>Mute</button><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="false"><span class="tui-lamp" data-lamp="green" aria-hidden="true"></span>Solo</button></div>
```

### Words alone

```html
<div style="display:flex;gap:10px"><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="true">Bold</button><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="false">Italic</button></div>
```

### A glyph · --icon

```html
<div style="display:flex;gap:10px"><button class="tui-key tui-toggle-key tui-key--icon" type="button" tabindex="-1" aria-pressed="true" aria-label="Favourite"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m8 2.6 1.6 3.3 3.6.5-2.6 2.5.6 3.6L8 10.8l-3.2 1.7.6-3.6L2.8 6.4l3.6-.5z"/></svg></button><button class="tui-key tui-toggle-key tui-key--icon" type="button" tabindex="-1" aria-pressed="false" aria-label="Alerts"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 11.2V7.3a4 4 0 0 1 8 0v3.9l1.3 1.3H2.7z"/><path d="M6.7 14.3h2.6"/></svg></button></div>
```

### Small · --sm

```html
<div style="display:flex;gap:8px"><button class="tui-key tui-toggle-key tui-key--sm" type="button" tabindex="-1" aria-pressed="true"><span class="tui-lamp" data-lamp="red" aria-hidden="true"></span>Errors</button><button class="tui-key tui-toggle-key tui-key--sm" type="button" tabindex="-1" aria-pressed="false"><span class="tui-lamp" data-lamp="amber" aria-hidden="true"></span>Warnings</button></div>
```

### A lamp of each colour

```html
<div style="display:flex;gap:10px;flex-wrap:wrap"><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="true"><span class="tui-lamp" data-lamp="green" aria-hidden="true"></span>Green</button><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="true"><span class="tui-lamp" data-lamp="amber" aria-hidden="true"></span>Amber</button><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="true"><span class="tui-lamp" data-lamp="red" aria-hidden="true"></span>Red</button><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="true"><span class="tui-lamp" data-lamp="blue" aria-hidden="true"></span>Blue</button></div>
```

### Disabled, up and down

```html
<div style="display:flex;gap:10px"><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="false" disabled>Armed</button><button class="tui-key tui-toggle-key" type="button" tabindex="-1" aria-pressed="true" disabled>Armed</button></div>
```

## Every state

- Up
- Hover
- Pressing
- Latched
- Focus
- 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 | with aria-pressed="true" or "false" | The key. Down is aria-pressed="true": the cap sinks below the plate and its lamp lights. |
| data-toggle-key | attribute | on the key | The script flips aria-pressed on press. Leave it off to set aria-pressed from your own state. |
| aria-pressed | attribute | "true" \| "false" | The state, for the page and for a screen reader. Start every toggle key with one or the other. |
| aria-label | attribute | on a key with no words | Names a key that shows only a glyph. Keep the name the same whether it is up or down. |
| .tui-lamp | class | inside the key, with data-lamp | The key’s own lamp: green, amber, red or blue. It is dark while the key is up and lit while it is down. |
| --sm · --icon | modifier | on the key | The key’s sizes; --icon makes a square cap for a glyph. |
| tui-toggle-key-change | event | detail { pressed } | Bubbles from the key after it latches or lets go. |
| toggleKey(key, force?) | function | a key, and true or false | Latches, releases or flips a key from code, fires the event and returns the new state. |
| Space · Enter | key | on the key | Latch it or let it go; it is a button, so both work. |

## Markup

```html
<!-- Words, with a lamp that lights while the key is down -->
<button class="tui-key tui-toggle-key" type="button" data-toggle-key aria-pressed="false">
  <span class="tui-lamp" data-lamp="amber" aria-hidden="true"></span>Mute
</button>

<!-- A glyph alone: the name is the same up or down, aria-pressed says which -->
<button class="tui-key tui-key--icon tui-toggle-key" type="button" data-toggle-key aria-pressed="true" aria-label="Favourite">
  <svg class="tui-icon" …></svg>
</button>

<!-- Without data-toggle-key you keep aria-pressed yourself, as a framework would -->
<button class="tui-key tui-toggle-key" type="button" aria-pressed="true">Pinned</button>
```

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

const mute = document.querySelector('#mute');
mute.addEventListener('tui-toggle-key-change', (e) => {
  channel.muted = e.detail.pressed;           // true while the key is down
});

toggleKey(mute, true);   // latch it from code
toggleKey(mute);         // flip it
```

The demo on the page:

```html
<div class="tui-panel" style="width:min(100%,420px);display:grid;gap:16px;text-align:left"><div class="tui-panel__head" style="margin-bottom:0"><span class="tui-label">Channel 3 · Strings</span><span class="tui-status"><span class="tui-lamp" data-on></span>Live</span></div>
  <div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center" data-tk-demo>
    <button class="tui-key tui-toggle-key" type="button" data-toggle-key aria-pressed="false" data-tk="mute"><span class="tui-lamp" data-lamp="amber" aria-hidden="true"></span>Mute</button>
    <button class="tui-key tui-toggle-key" type="button" data-toggle-key aria-pressed="false" data-tk="solo"><span class="tui-lamp" data-lamp="green" aria-hidden="true"></span>Solo</button>
    <button class="tui-key tui-toggle-key tui-key--icon" type="button" data-toggle-key aria-pressed="false" aria-label="Favourite" data-tk="star"><svg class="tui-icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m8 2.6 1.6 3.3 3.6.5-2.6 2.5.6 3.6L8 10.8l-3.2 1.7.6-3.6L2.8 6.4l3.6-.5z"/></svg></button>
    <button class="tui-key tui-toggle-key" type="button" data-toggle-key aria-pressed="true" data-tk="lock" disabled>Locked</button>
  </div>
  <output class="tui-muted" style="font-size:var(--tui-t-small)" data-tk-out aria-live="polite">Nothing is on</output></div>
```

## Usage notes

Press Mute and Solo: each stays down with its lamp lit, and the line underneath says what is on. The star is a key with no words, named for a screen reader. The last is disabled while it is down: it stays latched and cannot be changed.

## Accessibility

- It is a native `<button>` with `aria-pressed`, read as “Mute, toggle button, pressed”, and it works with Space and Enter.
- The state is the cap sunk below the plate and the lamp lit, and it is also in `aria-pressed`, so colour is never the only sign of it.
- The name stays the same up or down. A key that says “Mute” in both states is read right; one that changes to “Unmute” would be read as “Unmute, pressed”.
- A key that shows only a glyph is named with `aria-label`, and its glyph is hidden from a screen reader.
- On a phone the cap is 44px tall. The 70ms press is switched off under reduced motion; the state does not depend on it.

## How it’s built

There is almost nothing new under it. The kit’s key already sinks below the plate when it is pressed, and a pressed button is drawn the same way; this part only gives that latched look a meaning, one state kept. The lamp is the kit’s lamp, left unlit in the cap and lit by the key’s own pressed state, so it follows every finish and both volumes with no rule of its own. The script is one listener on the page that flips `aria-pressed` for any key that asks for it, so keys added later work without being wired.

## Rules

A single key that stays down: pressed and latched states a screen reader can read, a lamp that lights with it, and no switch where a key will do.

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

## Related parts

- [Key](https://tactileui.dev/parts/key): Every button, and every link that acts like one: a cap on a skirt that drops below the plate when pressed.
- [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.
- [Switch](https://tactileui.dev/parts/switch): On or off, applied the moment it moves. A native checkbox with a ridged thumb in a slot that lights green when on.
- [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.
