# Text & choices

> Tweakit's text input, checkbox, dropdown list and radio grid, each driving a live target.

The page: https://ryankiley.github.io/tweakit/text-and-choices.html. Every page as Markdown: https://ryankiley.github.io/tweakit/llms.txt

Strings, booleans and one-of-N choices. All four of these are built-in controls: they ship in the core bundle and are live the moment `tweaks()` returns.

## Text

A bare string is a text input (a color string becomes the picker). The verbose form adds `placeholder`, or `rows` to turn it into a textarea.

```js
const card = target.querySelector(".txt-card");
const panel = tweaks("Text", {
  headline: "Synthesizers",
  body: { type: "text", value: "Voltage in, music out.", rows: 3,
          placeholder: "Card body…" },
});
mount.append(panel.el);

const apply = (p) => {
  card.querySelector("h3").textContent = p.headline;
  card.querySelector("p").textContent = p.body;
};
panel.on(apply);
apply(panel.params);
```

`mount` is the panel's slot inside the stage; `target` is the demo surface it controls. In your own page you'd just `document.body.append(panel.el)`.

## Checkbox

`true` or `false` is all it takes. The control renders as an inline toggle pill; the param is a plain boolean.

```js
const badge = target.querySelector(".chk-badge");
const panel = tweaks("Checkbox", {
  enabled: true,
  color: true,
});
mount.append(panel.el);

const apply = (p) => {
  badge.style.opacity = p.enabled ? 1 : 0.25;
  badge.style.filter = p.color ? "none" : "grayscale(1)";
};
panel.on(apply);
apply(panel.params);
```

## List

An array of strings is a dropdown. Options can also be `{ value, label }` pairs when the displayed text shouldn't be the value. Here the value lands on `mix-blend-mode`. With the list open, typing moves to the option whose label starts with the letters you just typed, and the same letter again moves on to the next match; Enter or a click still picks it.

```js
const top = target.querySelector(".lst-b");
const panel = tweaks("List", {
  blend: ["normal", "screen", "overlay", "multiply", "difference",
          { value: "plus-lighter", label: "add (plus-lighter)" }],
});
mount.append(panel.el);

const apply = (p) => { top.style.mixBlendMode = p.blend; };
panel.on(apply);
apply(panel.params);
```

## Swatches in a list

An option can carry a `color`: it shows as a swatch beside the label in the dropdown and, for the chosen option, on the row. The param stays the string you gave it, so a token palette picks by name and your code applies whatever the name maps to.

```js
const card = target.querySelector(".sw-card");
const fills = { "neutral-10": "#f4f4f5", "neutral-90": "#18181b", accent: "#7C5CFF", warn: "#ff8a5b" };
const panel = tweaks("Tokens", {
  fill: { value: "neutral-10", options: [
    { value: "neutral-10", label: "Neutral 10", color: "#f4f4f5" },
    { value: "neutral-90", label: "Neutral 90", color: "#18181b" },
    { value: "accent",     label: "Accent",     color: "#7C5CFF" },
    { value: "warn",       label: "Warn",       color: "#ff8a5b" },
  ] },
});
mount.append(panel.el);

const apply = (p) => {
  card.style.background = fills[p.fill];
  card.style.color = p.fill === "neutral-10" ? "#222" : "#fff";
  card.textContent = panel.el.querySelector(".twk-select-value").textContent;
};
panel.on(apply);
apply(panel.params);
```

## Radio grid

A single-select laid out as buttons: `{ type: "radiogrid" }` (alias `"segmented"`) with `cols` (2 or 3) to shape the grid; a pill slides to the pick. With `label: ""` the row is all buttons, equal widths across it, and four fit on one line. Nine alignment options, three columns, and the value drops straight into `place-items`.

```js
const frame = target.querySelector(".rg-frame");
const panel = tweaks("Radio grid", {
  align: { type: "radiogrid", cols: 3, value: "center center", options: [
    { value: "start start", label: "↖" }, { value: "start center", label: "↑" }, { value: "start end", label: "↗" },
    { value: "center start", label: "←" }, { value: "center center", label: "·" }, { value: "center end", label: "→" },
    { value: "end start", label: "↙" }, { value: "end center", label: "↓" }, { value: "end end", label: "↘" },
  ] },
});
mount.append(panel.el);

const apply = (p) => { frame.style.placeItems = p.align; };
panel.on(apply);
apply(panel.params);
```
