Spec: correct two claims about select.js that were about to be built on
Both were checked only because the next commit would have depended on them, and both were wrong. There is no ten-option threshold in select.js. That judgement lives entirely in field-select.html, which decides whether to emit the opt-in; once a select carries data-rst-select it is enhanced and always gets a filter input. The spec had claimed the filter was suppressed below ten, which would have quietly given the three-option font control a search box while a comment asserted it had none. select.js does not handle disabled — the string does not appear in it. The three toolbar selects are disabled until the editor mounts, so the enhancement would have shipped a control that looks usable, takes focus and typing, and drives a disabled select. Mirroring that is ours to own. Two more consequences follow and are now written down: the combobox is the first control in the bar that holds a caret, so choosing a size has to hand focus back to the document, and the roving tabindex has to learn about an input where it currently only knows buttons.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XrHJFx6wn4VvTzc3drkTp4
1 file changed,
+49
−17
docs/superpowers/specs/2026-09-02-word-processor-basics-design.md+49 −17
diff --git a/docs/superpowers/specs/2026-09-02-word-processor-basics-design.md b/docs/superpowers/specs/2026-09-02-word-processor-basics-design.md| index 69ebd5e..8d86190 100644 |
| --- a/docs/superpowers/specs/2026-09-02-word-processor-basics-design.md |
| +++ b/docs/superpowers/specs/2026-09-02-word-processor-basics-design.md |
| @@ -338,27 +338,59 @@ hand-styled native `<select>`s. They become design-system comboboxes by |
| opting in — `rst-input`, `data-rst-select`, and the three |
| `data-rst-select-*` catalog strings `field-select.html` emits. |
| -Three things this must get right, none of which the opt-in gives for |
| +**Read `select.js` before designing against it.** Two things this spec |
| +asserted in its first draft are false, and both were checked only |
| +because they were about to be built on: |
| + |
| +- **There is no ten-option threshold in `select.js`.** That judgement |
| + lives entirely in `field-select.html`, which decides whether to emit |
| + the opt-in. Once a `<select>` carries `data-rst-select`, it is |
| + enhanced and it **always** gets a filter input. There is no |
| + suppression to rely on. |
| +- **`select.js` does not handle `disabled`.** The string does not |
| + appear in it. It mirrors value, options, `<optgroup>`s, `required` |
| + and reset — not the disabled state. |
| + |
| +Four things this must get right, none of which the opt-in gives for |
| free: |
| 1. **`select.js` builds an `[rst-combo]` wrapper containing a text |
| `input[role=combobox]` and a `ul[rst-combo-list]`** — a wider, |
| - input-shaped control where a compact select used to be. The |
| - `max-inline-size: 11rem` cap the selects carry has to move to the |
| - wrapper, or the bar grows and §3.4 fails. |
| -2. **The selects are `disabled` until the editor mounts.** An enhanced |
| - combobox over a disabled select is a control that looks usable and |
| - is not. The enhancement must mirror the disabled state, and |
| - `toolbar.mjs` must enable both halves when it enables the bar. |
| -3. **The framework's own judgement is that search below ten options is |
| - furniture, not help** (`field-select.html`: it emits the opt-in only |
| - past ten). Font has three options and block has four. After §6 the |
| - size select has eleven and earns it outright. Applying the |
| - enhancement to all three is Paul's explicit instruction and it is |
| - what makes the toolbar read as one design system rather than three |
| - native controls in a dark bar — but the *filter input* is suppressed |
| - below ten, so block and font get the design-system control without a |
| - search box that would filter four items. |
| + input-shaped control where a compact select used to be, with |
| + `width: 100%` on the input. The `max-inline-size: 11rem` cap the |
| + selects carry has to move to the wrapper, or the bar grows and §3.4 |
| + fails. |
| +2. **The three selects are `disabled` until the editor mounts**, and |
| + the enhancement will not honour that. Left alone, this ships a |
| + control that looks usable, accepts focus and typing, and drives a |
| + disabled select behind it. We mirror it ourselves: the enhancement |
| + runs, then `toolbar.mjs` enables or disables **both** halves |
| + together when it enables the bar. This is ours to own; it is not a |
| + framework bug to report. |
| +3. **The combobox is a text input, and the editor needs focus back.** |
| + Choosing a size must return the caret to the document, or a person |
| + sets 14pt and types into the font filter. Every existing toolbar |
| + control is a `<button>`, which does not have this problem; this is |
| + the first control in the bar that holds a caret of its own. |
| +4. **The roving tabindex has to learn about it.** `toolbar-roving.mjs` |
| + collects controls under the toolbar root; the native `<select>` gets |
| + `tabindex="-1"` and `aria-hidden="true"` from the enhancement, and |
| + the new input is what a person actually reaches. The bar must stay |
| + one tab stop with the arrow keys moving across nine buttons and |
| + three comboboxes. |
| + |
| +**All three selects opt in, and the framework's own comment disagrees |
| +with that.** `field-select.html` says search below ten options is |
| +"furniture, not help", and font has three options and block has four. |
| +Opting in all three is Paul's explicit instruction, and it is also the |
| +better call for a reason the framework's threshold cannot see: these |
| +three sit *side by side in one group*, and one combobox flanked by two |
| +native selects looks worse than either extreme. All three are also |
| +growth surfaces — §6 takes size to eleven immediately, spec §11.2 |
| +commits to named styles in the block list, and the face list is |
| +designed to grow. The tension is recorded rather than resolved silently: |
| +if the filter over three fonts reads as silly in the morning, the fix is |
| +one attribute, not a redesign. |
| ## 6. Font size |