Surfaced while fixing epic #987 (memory/CPU audit 2026-08). Not fixed there to keep those PRs surgical.
What's wrong
apps/desktop/src/renderer/src/components/tabs/tab-bar-with-drag.tsx:111-117 — the effect that keeps the active tab visible requests a smooth scroll unconditionally, with no prefers-reduced-motion check:
useLayoutEffect(() => {
if (!activeTabId || activeDragItem) return
const tabEl = scrollRef.current?.querySelector(`[data-tab-id="${CSS.escape(activeTabId)}"]`)
// scrollIntoView is not implemented in jsdom
tabEl?.scrollIntoView?.({ inline: 'nearest', block: 'nearest', behavior: 'smooth' })
}, [activeTabId, regularTabsLength, activeDragItem, canScrollToStart, canScrollToEnd])
The rest of the tab-strip motion in this folder acknowledges the requirement — components/tabs/animations.ts:42 defines tabVariantsReduced (a near-instant opacity-only variant, asserted in tabs-small-components.test.tsx:52) — but nothing gates this call. Per spec the behavior option overrides the CSS scroll-behavior property, so the existing @media (prefers-reduced-motion: reduce) blocks in assets/base.css cannot suppress it either; it has to be handled in JS.
Note tabVariantsReduced is currently exported and unit-tested but has no component consumer, so the reduced-motion path for the tab strip as a whole may be worth checking at the same time.
Why it matters
The repo targets WCAG AA plus reduced-motion (see CLAUDE.md / PRODUCT.md). A user who has asked their OS to reduce motion still gets an animated horizontal slide of the tab strip on every tab activation — one of the most frequently repeated interactions in the app. For motion-sensitive users this is exactly the kind of repeated involuntary movement the preference exists to suppress.
PR #1277 (for #1105) reduced this from up to 3 scheduled smooth scrolls per activation down to 1 by stabilising the effect deps, but did not add the preference gate — so the frequency improved and the a11y gap did not.
Suggested direction
Read the motion preference at call time and pass behavior: 'auto' when reduce is set (matchMedia('(prefers-reduced-motion: reduce)') — components/onboarding/use-first-run-tour.ts:33 already does this in the renderer, so there is a precedent to follow rather than a new pattern to invent). Whoever picks this up should check whether a shared hook is warranted given tabVariantsReduced's missing consumer, and confirm the jsdom-guarded optional call still tests cleanly.
Confirmed on
origin/main @ 2ba7f5950 on 2026-08-12.
Surfaced while fixing epic #987 (memory/CPU audit 2026-08). Not fixed there to keep those PRs surgical.
What's wrong
apps/desktop/src/renderer/src/components/tabs/tab-bar-with-drag.tsx:111-117— the effect that keeps the active tab visible requests a smooth scroll unconditionally, with noprefers-reduced-motioncheck:The rest of the tab-strip motion in this folder acknowledges the requirement —
components/tabs/animations.ts:42definestabVariantsReduced(a near-instant opacity-only variant, asserted intabs-small-components.test.tsx:52) — but nothing gates this call. Per spec thebehavioroption overrides the CSSscroll-behaviorproperty, so the existing@media (prefers-reduced-motion: reduce)blocks inassets/base.csscannot suppress it either; it has to be handled in JS.Note
tabVariantsReducedis currently exported and unit-tested but has no component consumer, so the reduced-motion path for the tab strip as a whole may be worth checking at the same time.Why it matters
The repo targets WCAG AA plus reduced-motion (see
CLAUDE.md/PRODUCT.md). A user who has asked their OS to reduce motion still gets an animated horizontal slide of the tab strip on every tab activation — one of the most frequently repeated interactions in the app. For motion-sensitive users this is exactly the kind of repeated involuntary movement the preference exists to suppress.PR #1277 (for #1105) reduced this from up to 3 scheduled smooth scrolls per activation down to 1 by stabilising the effect deps, but did not add the preference gate — so the frequency improved and the a11y gap did not.
Suggested direction
Read the motion preference at call time and pass
behavior: 'auto'when reduce is set (matchMedia('(prefers-reduced-motion: reduce)')—components/onboarding/use-first-run-tour.ts:33already does this in the renderer, so there is a precedent to follow rather than a new pattern to invent). Whoever picks this up should check whether a shared hook is warranted giventabVariantsReduced's missing consumer, and confirm the jsdom-guarded optional call still tests cleanly.Confirmed on
origin/main@2ba7f5950on 2026-08-12.