Give off switches and disabled primary buttons light-mode contrast

In the light theme an off switch's track was the input grey at ~1.4:1
on the card, and a disabled primary button was white on a half-opacity
violet at ~2:1. An off track now has its own token at ~3.5:1, and a
disabled primary button a pale violet fill with a dark violet label at
~5.5:1. The dark theme keeps its look through the same tokens.
This commit is contained in:
Marc-André Bombeck committed 2026-10-08 19:17:50 +02:00
1 parent 28458448c2
commit e227f8e4f3
3 files changed
+30 -2

No files matched your search

+25
View File
@@ -106,6 +106,9 @@
--color-chart-1: var(--chart-1);
--color-ring: var(--ring);
--color-input: var(--input);
--color-switch-off: var(--switch-off);
--color-primary-disabled: var(--primary-disabled);
--color-primary-disabled-foreground: var(--primary-disabled-foreground);
--color-input-focus: var(--input-focus);
--color-border: var(--border);
--color-destructive: var(--destructive);
@@ -292,6 +295,19 @@
--destructive: #ff5555;
--border: #44475a;
--input: #44475a;
/* An off switch's track, and a disabled primary button. Dark keeps the
* look these had (input at 80 %, primary at half strength). */
--switch-off: color-mix(in oklab, var(--input) 80%, transparent);
--primary-disabled: color-mix(
in oklab,
var(--primary) 50%,
var(--background)
);
--primary-disabled-foreground: color-mix(
in oklab,
var(--primary-foreground) 70%,
var(--primary-disabled)
);
/* Text-field focus border: a neutral, foreground-based tone, no colour
* ring. ~5.2:1 on --background, ~6:1 on --card. */
--input-focus: #9a9b9d;
@@ -423,6 +439,15 @@
--success-foreground: #ffffff;
--border: oklch(0.885 0.008 300);
--input: oklch(0.87 0.009 300);
/* An off switch's track: the input grey sat at ~1.4:1 on the card, so an
* off switch all but vanished. ~3.5:1 on --card clears the 3:1 floor for
* a control boundary. *
--switch-off: oklch(0.62 0.012 295);
/* A disabled primary button: opacity-50 left white text on a washed
* violet at ~2:1. A pale violet fill with a dark violet label (~5.5:1)
* still reads as the primary action, and as unavailable. */
--primary-disabled: oklch(0.88 0.035 290);
--primary-disabled-foreground: oklch(0.44 0.06 290);
/* Text-field focus border, neutral: ~4.2:1 on --background. */
--input-focus: oklch(0.56 0.012 295);
--ring: oklch(0.48 0.012 290); /* neutral: no purple focus frames anywhere */
+4 -1
View File
@@ -34,7 +34,10 @@ const buttonVariants = cva(
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
// Disabled keeps its label readable in both themes: a token pair
// rather than half opacity (white on a washed violet, ~2:1 light).
default:
"bg-primary text-primary-foreground hover:bg-primary/90 disabled:bg-primary-disabled disabled:text-primary-disabled-foreground disabled:opacity-100",
destructive:
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
+1 -1
View File
@@ -25,7 +25,7 @@ function Switch({
// without disturbing layout. v1.4.43 W10 design-M1 — `-13px` (not
// `-12px`) takes the 18.4 px track + 26 px padding to 44.4 px and
// closes the 1.6 px vertical short fall to spec-strict 2.5.5.
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none before:absolute before:inset-[-13px] before:content-[''] focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6",
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-switch-off focus-visible:border-ring focus-visible:ring-ring/50 group/switch relative inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none before:absolute before:inset-[-13px] before:content-[''] focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6",
className,
)}
{...props}