# UX rules: rationale The reasoning behind the UX rules in [`docs/STYLEGUIDE.md`](../STYLEGUIDE.md#ux-rules). Read when a rule's application is unclear or you need to justify a divergence. ## 1. Match in-flight feedback to perceived duration The right question isn't _"should this control change while it's working?"_ — it's _"how long does the action take, and what does the user need to know during that time?"_ | Duration | Feedback | | ------------------ | --------------------------------------------- | | 0–100 ms | None. Anything visible reads as a glitch. | | 100 ms–1 s | Disabled state only. | | 1 s–3 s | Disabled + spinner or label swap. | | 3 s+ or multi-step | Stage labels, progress, optional reassurance. | Two corollaries: - **Pre-reserve any space you'll later occupy.** If a control may swap to a longer label or grow an icon, fix its footprint up front (use `width`, not `min-width`). A control that resizes mid-action looks broken even when the action succeeded. - **Don't pick worst-case feedback for everyone.** If the action is fast locally and slow remotely (SSH), defer the visible loading state by ~200ms. Local users see nothing; remote users get appropriate feedback. Bind the _disabled_ state immediately (so double-clicks don't double-submit) and the _visible_ state on a timer. ## 2. Look for sibling components before designing in isolation If your component has a sibling — same domain, overlapping behavior, often visible at adjacent moments in the same flow — the two should read as one design. Same icons, same shortcut conventions, same submit semantics. A user moving between them shouldn't perceive a seam. This is _not_ "match every existing pattern." Some repo patterns are debt and copying them spreads the debt. The narrower claim is about _adjacent_ components. Diverging from a sibling needs a reason: either the sibling is wrong (fix both) or the new component has a real difference in role (commit to it). When there's no sibling, match the surrounding chrome — button sizes, icon weights, copy tone — and don't manufacture a sibling from a screen the user will never correlate with this one. ## 3. Don't overload the back-out path `destructive` is for actions that lose data or can't be undone. **Cancel, Dismiss, Close, and Discard are not destructive** — they back the user out of an in-progress action and should stay quiet (default ghost button, no color, no keyboard chip, no animated affordance). Save the visual weight for the affirmative action so the two don't compete. Keyboard handlers can still honor Esc; the visible decoration is what stays minimal.