Toggle switch feels nicer to toggle (#4749)

Two small tweaks to the `Switch` primitive, so every variant and call
site picks them up:

1. **Track is 2px shorter.** `large` 44 → 42px, `medium` 32 → 30px,
`small` 24 → 22px. The checked thumb travel drops by the same 2px so the
thumb stays flush at both ends.
2. **Holding the switch down stretches the thumb into an oval** pointing
the way it's about to travel — rightwards when off, leftwards when on.
Pure CSS via `group-active:`, no new state or handlers.

The thumb's `transition` shorthand doesn't cover `width`, so it's now
`transition-[translate,width,background-color]` (same 150ms
duration/easing as before). `size-N` on the thumb became `h-N w-N` so
the press rule overrides the same `width` utility.

Verified in headless Chrome across all five variants in both states:
correct widths at rest, thumb flush at both ends, stretch grows the
right direction, and no overflow of the track.

<img width="266" height="108" alt="CleanShot 2026-08-21 at 10 16 14"
src="https://github.com/user-attachments/assets/ee95a399-0a40-48c4-a325-a1166b3bd88a"
/>


🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- conductor-workspace-link -->

---

[Open workspace in
Conductor](https://app.conductor.build/workspace/c1ce8d0f-9ed2-4fbc-8084-a3989484cc53)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
James Ritchie
2026-08-21 10:24:29 +01:00
committed by GitHub
parent d04467018e
commit 2efb07e0b1
@@ -8,16 +8,22 @@ import { type ShortcutDefinition, useShortcutKeys } from "~/hooks/useShortcutKey
const small = {
container:
"flex items-center h-6 gap-x-1.5 rounded hover:bg-tertiary pr-1 py-[0.1rem] pl-1.5 hover:disabled:bg-background-raised transition focus-custom disabled:opacity-50 text-text-dimmed hover:text-text-bright disabled:hover:cursor-not-allowed hover:cursor-pointer disabled:hover:text-rose-500",
root: "h-3 w-6",
thumb: "size-2.5 data-[state=checked]:translate-x-2.5 data-[state=unchecked]:translate-x-0",
root: "h-3 w-5.5",
thumb: cn(
"h-2.5 w-2.5 data-[state=checked]:translate-x-2 data-[state=unchecked]:translate-x-0",
"group-active:w-3.25 group-active:data-[state=checked]:translate-x-1.25"
),
text: "text-xs text-text-dimmed",
};
const variations = {
large: {
container: "flex items-center gap-x-2 rounded-md hover:bg-tertiary p-2 transition focus-custom",
root: "h-6 w-11",
thumb: "size-5 data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0",
root: "h-6 w-10.5",
thumb: cn(
"h-5 w-5 data-[state=checked]:translate-x-4.5 data-[state=unchecked]:translate-x-0",
"group-active:w-6.5 group-active:data-[state=checked]:translate-x-3"
),
text: "text-sm text-text-dimmed",
},
small,
@@ -48,8 +54,11 @@ const variations = {
medium: {
container:
"flex items-center gap-x-2 rounded-md hover:bg-tertiary py-1.5 px-2 transition focus-custom",
root: "h-4 w-8",
thumb: "size-3.5 data-[state=checked]:translate-x-3.5 data-[state=unchecked]:translate-x-0",
root: "h-4 w-7.5",
thumb: cn(
"h-3.5 w-3.5 data-[state=checked]:translate-x-3 data-[state=unchecked]:translate-x-0",
"group-active:w-4.5 group-active:data-[state=checked]:translate-x-2"
),
text: "text-sm text-text-dimmed",
},
};
@@ -96,7 +105,7 @@ export const Switch = React.forwardRef<React.ElementRef<typeof SwitchPrimitives.
<SwitchPrimitives.Thumb
className={cn(
thumb,
"pointer-events-none block rounded-full bg-white transition dark:bg-charcoal-200 dark:group-data-[state=checked]:bg-text-bright"
"pointer-events-none block rounded-full bg-white transition-[translate,width,background-color] dark:bg-charcoal-200 dark:group-data-[state=checked]:bg-text-bright"
)}
/>
</div>