From 3d07613c2bc96c21aa9f74de23bc7a3ca2ca8dd0 Mon Sep 17 00:00:00 2001 From: Danny White <3104761+dnywh@users.noreply.github.com> Date: Mon, 20 Jul 2026 10:59:34 -0400 Subject: [PATCH] fix(ui): restore text-contrast token (#48017) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Bug fix ## What is the current behavior? `text-contrast` / `text-foreground-contrast` resolve to `--primary-foreground`, which is always the darker of surface / foreground lightness (text for the green primary fill). In light mode that is near-black, so contrast text on inverted fills is wrong: on true black (`bg-black`) it disappears; on dark fills like `bg-red-900` it shows as a black icon instead of white. Visible regression on the design-system colour usage page: the `text-contrast` swatch only shows "Postgres" on hover. Regression from the colour system rewrite (#47288), which aliased `--foreground-contrast` → `--primary-foreground`. ## What is the new behavior? `--foreground-contrast` is defined again as a surface-based inverse of `--foreground` (light in light mode, dark in dark mode). Tailwind utilities `text-contrast` and `text-foreground-contrast` map to it. `--primary-foreground` is unchanged and still used for text on the primary fill. ## Additional context ### Callsites to test (light mode especially) | Where to look | What to check | |---|---| | [Design system → Colour usage](https://design-system-git-fix-text-contrast-token-supabase.vercel.app/design-system/docs/color-usage) | Under **Text**, the `text-contrast` swatch shows "Postgres" without hovering | | [Studio staging → Auth Users](https://studio-staging-git-fix-text-contrast-token-supabase.vercel.app/project/_/auth/users) → open any user | Boolean fields (e.g. confirmed): check/X on the black circle should be **white** (not missing) | | [Studio staging → Support new](https://studio-staging-git-fix-text-contrast-token-supabase.vercel.app/support/new) → upload a file | Red remove (`X`) badge should be a **white** X (prod currently shows black) | | [www → Contribute](https://zone-www-dot-com-git-fix-text-contrast-token-supabase.vercel.app/contribute) → apply at least one filter | Filter count badge: **white** number on black | | [Studio staging → Support link](https://studio-staging-git-fix-text-contrast-token-supabase.vercel.app/support/link) success state (after linking a ticket) | Check on the brand badge should use contrast text (light on brand in light mode) | `Announcement` (`text-foreground-contrast` dismiss icon) is not currently mounted in any app — covered by the design-system / token check above. --- packages/config/css/theme.css | 4 ++-- packages/ui/build/css/source/compat.css | 2 +- packages/ui/build/css/source/semantic.css | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/config/css/theme.css b/packages/config/css/theme.css index 081452ba09f..71b0255cd58 100644 --- a/packages/config/css/theme.css +++ b/packages/config/css/theme.css @@ -37,7 +37,7 @@ --color-foreground-light: var(--muted-foreground); --color-foreground-lighter: var(--tertiary-foreground); --color-foreground-muted: var(--foreground-muted); - --color-foreground-contrast: var(--primary-foreground); + --color-foreground-contrast: var(--foreground-contrast); --color-background-200: var(--background-200); --color-background-alternative-200: var(--background-alternative-200); --color-background-alternative: var(--background-alternative-default); @@ -346,7 +346,7 @@ --text-color-light: var(--muted-foreground); --text-color-lighter: var(--tertiary-foreground); --text-color-muted: var(--foreground-muted); - --text-color-contrast: var(--primary-foreground); + --text-color-contrast: var(--foreground-contrast); /* misc theme tokens — typography, breakpoints, sizing, transform-origin */ --font-sans: var( diff --git a/packages/ui/build/css/source/compat.css b/packages/ui/build/css/source/compat.css index f2806ed468b..23ea0b3b44d 100644 --- a/packages/ui/build/css/source/compat.css +++ b/packages/ui/build/css/source/compat.css @@ -16,7 +16,7 @@ --foreground-light: var(--muted-foreground); --foreground-lighter: var(--tertiary-foreground); --foreground-muted: var(--tertiary-foreground); - --foreground-contrast: var(--primary-foreground); + /* --foreground-contrast lives in semantic.css — do not remap to --primary-foreground */ /* Legacy background aliases */ --background-default: var(--background); diff --git a/packages/ui/build/css/source/semantic.css b/packages/ui/build/css/source/semantic.css index 4734b7144f6..2e205a4c7cc 100644 --- a/packages/ui/build/css/source/semantic.css +++ b/packages/ui/build/css/source/semantic.css @@ -143,6 +143,10 @@ calc(var(--surface) + var(--tone-span) * var(--contrast-text)) calc(var(--chroma) * 0.55) var(--surface-hue) ); + /* Inverse of --foreground: canvas-coloured text for use on inverted fills + (bg-foreground, bg-black / dark:bg-white, etc). Not the same as + --primary-foreground, which stays dark for the vivid primary fill. */ + --foreground-contrast: oklch(var(--surface) calc(var(--chroma) * 0.55) var(--surface-hue)); --card: oklch(from var(--background) calc(l + var(--elevation-step) * var(--elevation-1)) c h); --card-foreground: var(--foreground);