Mobile key bar — two rows, no horizontal scroll
Reflow the mobile soft key bar from a single overflow-x row into two rows so every key is reachable without horizontal scrolling. Plan + layout options + test/evidence strategy.
Implemented in
#1181 . Branch mobile-keybar-two-row. Plan of
record for the /be run — Option B (fixed six-column grid) shipped, current
key order kept. (As shipped, the column count is derived —
COLS = ceil(controls / 2) — and applied via an inline grid-template-columns,
not a literal grid-cols-6 class, which Tailwind would purge.)
Today
MobileKeyBar.tsx:88-89 renders all twelve controls in one flex row that scrolls
sideways:
class="flex gap-1 px-2 py-1.5 bg-surface-1 border-t border-edge overflow-x-auto"
The twelve controls, in DOM order, are the two sticky modifiers then ten keys:
| Ctrl | Alt | Esc | Tab | ⇧Tab | ↑ |
| ↓ | ← | → | ^C | / | ⏎ |
Each button is shrink-0 min-w-[2.5rem] (KEY_CLASS, line 65-66), so at ~40px +
gaps the row is ~520px wide and overflows a ~360px portrait viewport — hence the
scroll.
Approach — two candidate layouts
Recommended Option B — fixed grid-cols-6.
Replace flex … overflow-x-auto with grid grid-cols-6 gap-1. Twelve controls
flow row-major into exactly two rows of six, regardless of viewport width.
Drop shrink-0 min-w-[2.5rem] from KEY_CLASS so each cell stretches to fill its
column (the grid track sets the width now). The existing DOM order gives:
| Ctrl | Alt | Esc | Tab | ⇧Tab | ↑ |
|---|---|---|---|---|---|
| ↓ | ← | → | ^C | / | ⏎ |
Guarantees the “two rows” ask on every screen; no scroll container at all.
Option A — flex-wrap. Swap overflow-x-auto → flex-wrap, keep
min-w-[2.5rem]. Smaller diff, buttons keep their natural width and wrap. But the
row count is viewport-dependent — two on a typical phone, possibly three on a very
narrow one — so it doesn’t guarantee two rows. Rejected for not meeting the ask
precisely.
Files
packages/client/src/MobileKeyBar.tsx— container class swap (flex … overflow-x-auto→grid grid-cols-6); trimshrink-0 min-w-[2.5rem]fromKEY_CLASS. ~2 lines.
Test strategy (feature / new behavior)
Add an e2e assertion to the existing mobile-soft-keyboard.feature + steps
(mobile_soft_keyboard_steps.ts) that pins the new layout:
- No horizontal overflow: the
[data-testid="mobile-key-bar"]element hasscrollWidth <= clientWidth(the bug today isscrollWidth > clientWidth). - Two rows: the twelve
mobile-key-*buttons resolve to exactly two distinctoffsetTopvalues (row-major grid ⇒ all keys live on one of two baselines).
This is the covering test for the change; it fails red against the current single-row bar and green after the grid swap.
Evidence
Per .agency/do.md ## PR evidence — visible UI impact, so a screenshot of the
mobile key bar showing all twelve keys in two rows with nothing clipped. Captured
via the /evidence e2e-recording path on a pu box (mobile viewport).
Out of scope
Key set, escape sequences, sticky-modifier behavior, haptics, and the swipe guard are unchanged — this is purely a reflow of the existing controls.