# Install snippet

One command, four package managers. A row of selector keys (npm, pnpm, yarn and bun) sits over a line of display glass with the command on it and the copy key at the end. Press another key and the command is rewritten; the choice is remembered, and every other install snippet on the page follows it, so someone who uses pnpm reads pnpm all the way down the guide. It is the kit’s selector and copy key with one small script between them.

Kit part · Free · https://tactileui.dev/parts/install-snippet

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

## Variants

### Add · the default

```html
<div style="width:min(480px,calc(100vw - 96px));text-align:left"><div class="tui-install" data-install data-pkg="@northwind/cli"><div class="tui-seg tui-seg--sm" role="radiogroup" aria-label="Package manager"><label><input type="radio" name="pm-v1" value="npm" checked><span>npm</span></label><label><input type="radio" name="pm-v1" value="pnpm"><span>pnpm</span></label><label><input type="radio" name="pm-v1" value="yarn"><span>yarn</span></label><label><input type="radio" name="pm-v1" value="bun"><span>bun</span></label></div><div class="tui-glass tui-install__glass"><code class="tui-install__cmd" id="pm-v1-cmd">npm install @northwind/cli</code><button class="tui-key tui-key--flat tui-key--sm tui-copy-key" type="button" data-copy-from="#pm-v1-cmd" aria-label="Copy install command"></button></div></div></div>
```

### Add as a development dependency · data-mode="dev"

```html
<div style="width:min(480px,calc(100vw - 96px));text-align:left"><div class="tui-install" data-install data-pkg="@northwind/lint" data-mode="dev"><div class="tui-seg tui-seg--sm" role="radiogroup" aria-label="Package manager"><label><input type="radio" name="pm-v2" value="npm" checked><span>npm</span></label><label><input type="radio" name="pm-v2" value="pnpm"><span>pnpm</span></label><label><input type="radio" name="pm-v2" value="yarn"><span>yarn</span></label><label><input type="radio" name="pm-v2" value="bun"><span>bun</span></label></div><div class="tui-glass tui-install__glass"><code class="tui-install__cmd" id="pm-v2-cmd">npm install -D @northwind/lint</code><button class="tui-key tui-key--flat tui-key--sm tui-copy-key" type="button" data-copy-from="#pm-v2-cmd" aria-label="Copy install command"></button></div></div></div>
```

### Install globally · data-mode="global"

```html
<div style="width:min(480px,calc(100vw - 96px));text-align:left"><div class="tui-install" data-install data-pkg="@northwind/cli" data-mode="global"><div class="tui-seg tui-seg--sm" role="radiogroup" aria-label="Package manager"><label><input type="radio" name="pm-v3" value="npm" checked><span>npm</span></label><label><input type="radio" name="pm-v3" value="pnpm"><span>pnpm</span></label><label><input type="radio" name="pm-v3" value="yarn"><span>yarn</span></label><label><input type="radio" name="pm-v3" value="bun"><span>bun</span></label></div><div class="tui-glass tui-install__glass"><code class="tui-install__cmd" id="pm-v3-cmd">npm install -g @northwind/cli</code><button class="tui-key tui-key--flat tui-key--sm tui-copy-key" type="button" data-copy-from="#pm-v3-cmd" aria-label="Copy install command"></button></div></div></div>
```

### Run once · data-mode="exec"

```html
<div style="width:min(480px,calc(100vw - 96px));text-align:left"><div class="tui-install" data-install data-pkg="@northwind/cli init" data-mode="exec"><div class="tui-seg tui-seg--sm" role="radiogroup" aria-label="Package manager"><label><input type="radio" name="pm-v4" value="npm" checked><span>npm</span></label><label><input type="radio" name="pm-v4" value="pnpm"><span>pnpm</span></label><label><input type="radio" name="pm-v4" value="yarn"><span>yarn</span></label><label><input type="radio" name="pm-v4" value="bun"><span>bun</span></label></div><div class="tui-glass tui-install__glass"><code class="tui-install__cmd" id="pm-v4-cmd">npx @northwind/cli init</code><button class="tui-key tui-key--flat tui-key--sm tui-copy-key" type="button" data-copy-from="#pm-v4-cmd" aria-label="Copy install command"></button></div></div></div>
```

### A long package name wraps

```html
<div style="width:min(300px,calc(100vw - 96px));text-align:left"><div class="tui-install" data-install data-pkg="@northwind/harbour-schedules-and-tides-client"><div class="tui-seg tui-seg--sm" role="radiogroup" aria-label="Package manager"><label><input type="radio" name="pm-v5" value="npm" checked><span>npm</span></label><label><input type="radio" name="pm-v5" value="pnpm"><span>pnpm</span></label><label><input type="radio" name="pm-v5" value="yarn"><span>yarn</span></label><label><input type="radio" name="pm-v5" value="bun"><span>bun</span></label></div><div class="tui-glass tui-install__glass"><code class="tui-install__cmd" id="pm-v5-cmd">npm install @northwind/harbour-schedules-and-tides-client</code><button class="tui-key tui-key--flat tui-key--sm tui-copy-key" type="button" data-copy-from="#pm-v5-cmd" aria-label="Copy install command"></button></div></div></div>
```

## Every state

- npm
- pnpm
- yarn
- bun

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 |
| - | - | - | - |
| .tui-install[data-install][data-pkg] | element | the package | The snippet. data-pkg is the package, or the package and its arguments for exec. Use a name of your own. |
| [data-mode] | attribute | add · dev · global · exec | What the command does. Add is the default; exec runs the package once without installing it. |
| .tui-seg[role="radiogroup"] > label > input[type="radio"] | element | npm · pnpm · yarn · bun | The selector. Each radio’s value is the manager, and each group needs a name of its own: two groups with one name are one group to the browser. |
| code.tui-install__cmd | element | the command | On glass, with the prompt drawn in the margin by the stylesheet, so it is never copied. The script rewrites its text. |
| button.tui-copy-key[data-copy-from] | element | points at the command’s id | The kit’s copy key: it copies whatever the command says now. |
| [data-install-fixed] | attribute | on the snippet | Keeps a snippet on its own choice, for a demonstration. It still rewrites itself when pressed. |
| tui-install-manager | event | bubbles | Fired on the snippet that was changed, with detail { manager }. |
| installCommand(manager, pkg, mode) | function | pure | The command for a manager, a package and a mode. An unknown manager or mode falls back to npm and add. |
| setInstallManager(manager) · installRemembered() | function | needs kit.mjs | Set every snippet and remember it as tui-pm; read the remembered choice back, or an empty string. |

## Markup

```html
<!-- A native radio group of keys, a line of glass, the copy key. Each snippet's radios need a name of their own. -->
<div class="tui-install" data-install data-pkg="@northwind/cli">
  <div class="tui-seg tui-seg--sm" role="radiogroup" aria-label="Package manager">
    <label><input type="radio" name="pm-1" value="npm" checked><span>npm</span></label>
    <label><input type="radio" name="pm-1" value="pnpm"><span>pnpm</span></label>
    <label><input type="radio" name="pm-1" value="yarn"><span>yarn</span></label>
    <label><input type="radio" name="pm-1" value="bun"><span>bun</span></label>
  </div>
  <div class="tui-glass tui-install__glass">
    <code class="tui-install__cmd" id="pm-1-cmd">npm install @northwind/cli</code>
    <button class="tui-key tui-key--flat tui-key--sm tui-copy-key" type="button" data-copy-from="#pm-1-cmd" aria-label="Copy install command"></button>
  </div>
</div>

<!-- data-mode: dev, global or exec (run once, no install). data-install-fixed: stays on its own choice. -->
```

```js
import { setInstallManager, installCommand } from '/kit/kit.mjs';

installCommand('pnpm', '@northwind/cli', 'dev');     // "pnpm add -D @northwind/cli"
setInstallManager('bun');                              // every snippet, remembered as tui-pm

document.addEventListener('tui-install-manager', (e) => track(e.detail.manager));
```

The demo on the page:

```html
<div style="display:grid;gap:20px;width:min(100%,520px);text-align:left">
  <div style="display:grid;gap:6px"><span class="tui-label">1. Add it to your project</span><div class="tui-install" data-install data-pkg="@northwind/cli"><div class="tui-seg tui-seg--sm" role="radiogroup" aria-label="Package manager"><label><input type="radio" name="pm-d1" value="npm" checked><span>npm</span></label><label><input type="radio" name="pm-d1" value="pnpm"><span>pnpm</span></label><label><input type="radio" name="pm-d1" value="yarn"><span>yarn</span></label><label><input type="radio" name="pm-d1" value="bun"><span>bun</span></label></div><div class="tui-glass tui-install__glass"><code class="tui-install__cmd" id="pm-d1-cmd">npm install @northwind/cli</code><button class="tui-key tui-key--flat tui-key--sm tui-copy-key" type="button" data-copy-from="#pm-d1-cmd" aria-label="Copy install command"></button></div></div></div>
  <div style="display:grid;gap:6px"><span class="tui-label">2. Or run it once</span><div class="tui-install" data-install data-pkg="@northwind/cli init" data-mode="exec"><div class="tui-seg tui-seg--sm" role="radiogroup" aria-label="Package manager"><label><input type="radio" name="pm-d2" value="npm" checked><span>npm</span></label><label><input type="radio" name="pm-d2" value="pnpm"><span>pnpm</span></label><label><input type="radio" name="pm-d2" value="yarn"><span>yarn</span></label><label><input type="radio" name="pm-d2" value="bun"><span>bun</span></label></div><div class="tui-glass tui-install__glass"><code class="tui-install__cmd" id="pm-d2-cmd">npx @northwind/cli init</code><button class="tui-key tui-key--flat tui-key--sm tui-copy-key" type="button" data-copy-from="#pm-d2-cmd" aria-label="Copy install command"></button></div></div></div>
  <output class="tui-muted" style="font-size:var(--tui-t-small)" data-pm-out aria-live="polite"></output>
</div>
```

## Usage notes

Press yarn on the first snippet: its command changes, and so does the second one. Reload the page: the choice is still there. Tab to the keys and press an arrow key to move between them; Tab again to reach the copy key.

## Accessibility

- The managers are a native radio group with a name, so the arrow keys move between them, the chosen one is announced, and there is one tab stop for the row. Nothing is built from scratch.
- The chosen manager is also the first word of the command, so the line says what is selected whether or not the keys can be seen. Rewriting the command does not move focus.
- The prompt in the margin is drawn by the stylesheet with an empty alternative text: it is not read, selected or copied. The copy key takes only the command.
- Remembering the choice uses localStorage inside a try, so a browser that will not keep it still works for the page. Another tab’s choice arrives through the storage event.
- On a phone the keys and the copy key are 44px tall; a long package name wraps inside the glass and the page never scrolls sideways.

## How it’s built

The kit’s selector and the kit’s copy key, on a line of `.tui-glass`. The script is about forty lines: it builds the command from a table of four words per manager, delegates the radios’ change, and remembers the answer. The glass and the keys draw themselves in every finish and volume as they do elsewhere.

## Rules

Print the install command once and let the reader choose their package manager: the keys rewrite it, the copy key takes it, and the whole page remembers the choice.

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

## Related parts

- [Selector](https://tactileui.dev/parts/selector): One mode of two to five: latching keys in a tray, one down at a time, each with a lamp that lights when chosen.
- [Copy key](https://tactileui.dev/parts/copy-key): A key that copies a value and says so. Its lamp sits dark in the cap; when the text is on the clipboard the lamp lights, winks once, and the legend says Copied before it goes back to Copy. If the browser refuses the clipboard, the text is selected for the keyboard and the lamp lights amber.
- [Code block](https://tactileui.dev/parts/code-block): Code on display glass. A bar along the top holds the file name on a tab, with a lit edge under it, and the copy key at the far end. Under it the lines run, each with its number engraved in a gutter that stays where it is when a long line scrolls sideways. The numbers are drawn by the stylesheet, so they are never selected, never copied and never read aloud. Highlighting is optional and small: a few strengths of the display’s own light, told apart by weight and italic, never a colour of its own.
