Source:
ocean/docs/ui-ux/theming-ui-ux-assessment-2025-08-29.md| ✏️ Edit on GitHub
Ocean UI/UX Theming Assessment — 2025-08-29
Generated at 2025-08-29T11:33:03-04:00
Author: Design Systems & DX Audit
Executive Summary
- Architecture fit: The stack (Tailwind 4 +
@theme, CSS variables,next-themes,class-variance-authority, shadcn/ui components) is well aligned for scalable theming and long-term UI/UX evolution. - Strengths: Clear separation between semantic tokens and component usage; palette-driven themes; light/dark handled at the root; shadcn components consume semantic utilities.
- Gaps: Potential FOUC on palette switch, a stale
tokens.generated.cssartifact with wrong units, missing automated contrast checks, and lack of guardrails to prevent raw color usage. - Verdict: Ready to grow and customize shadcn/ui. Address the minor gaps to ensure robustness, a11y, and contributor ergonomics.
System Overview
- Color palettes:
design-tokens/palettes.jsondefines semantic colors (background, foreground, primary, etc.) with light and dark variants per palette (neutral,stone,zinc,gray,slate). - Runtime variables:
src/styles/color-themes.generated.csssets CSS variables for each palette via:root[data-color-theme]and.dark[…]overrides. - Tailwind mapping:
src/styles.cssmaps semantic CSS variables to Tailwind color tokens via@theme(e.g.,--color-primary: var(--primary)), enabling utilities likebg-primary,text-muted-foreground. - Dark mode:
next-themesinsrc/routes/__root.tsxcontrolsclass="dark"on the root. - Palette selection:
useColorTheme()insrc/hooks/use-color-theme.tswritesdata-color-themetodocument.documentElementand persists it inlocalStorage. - Components: shadcn/ui (e.g.,
src/components/ui/button.tsx) usecvavariants and semantic Tailwind utilities.
Diagram — Token and Theme Flow
Runtime Theming Integration
- Dark mode:
ThemeProvidersets.darkclass based on user/system preference. - Palette:
useColorTheme()setsdata-color-themeto match selected palette. - Result: CSS variables from
color-themes.generated.cssresolve for both light and dark.
Key files:
src/routes/__root.tsx— wraps app withThemeProvider.src/hooks/use-color-theme.ts— setsdata-color-theme+localStorage.src/styles/color-themes.generated.css— variables for each palette/mode.
Component Theming (shadcn/ui)
- Pattern: Use semantic Tailwind utilities that map to CSS vars (no raw colors).
- Example:
src/components/ui/button.tsxusescvavariants and classes likebg-primary,text-primary-foreground,border-border.
Guidelines:
- Do: add/extend
cvavariants; keep using semantic classes. - Avoid: hex/rgb/hsl/oklch literals in TSX/CSS; prefer variables/utilities.
Accessibility (Contrast)
- Pairs to verify (AA minimum, AAA preferred for text):
foregroundonbackgroundprimary-foregroundonprimarysecondary-foregroundonsecondarymuted-foregroundonmutedaccent-foregroundonaccentdestructive-foregroundondestructive
Developer Ergonomics & DX
- Pros:
- Single semantic surface for colors via Tailwind utilities.
cvavariants centralize component options.- Palettes can evolve without component churn.
- Improvements:
- Pre-hydration script to avoid FOUC.
- Guardrails (ESLint/CI) to block raw colors.
- Docs for shadcn customization and update policy.
Risks & Gaps
- FOUC risk:
data-color-themeset inuseEffect(post-paint). - Stale artifact:
src/styles/tokens.generated.cssappears unused and uses incorrect px units (fractions like0.625px). - No automated contrast checks.
- No lint rule preventing raw color usage in components.
- Minor duplication: sidebar token remapping can be consolidated.
Recommendations (Actionable)
- No-flash theming: Inline pre-hydration script in
index.htmlto setdata-color-themeearly;next-themesalready handles.darkpreflight. - Token cleanup: Remove or fix
src/styles/tokens.generated.css; keepsrc/styles/tokens.csscanonical (use rem units). - Contrast CI: Add
tools/check-contrast.tsto validate semantic pairs per palette/mode; gate PRs. - Guardrails: ESLint rule/CI grep to forbid color literals in
src/**/*.{ts,tsx,css}(allow in token/generator paths). - Docs: Short contributor doc on customizing shadcn components with tokens, and when to fork vs. extend.
- Optional: Generate TS types/metadata from
design-tokens/palettes.jsonto keepsrc/config/themes.tsin sync or replace it.
Implementation Plan (Phased)
-
Phase 1 (Same-day)
- Add pre-hydration no-flash script.
- Remove or correct
src/styles/tokens.generated.css. - Write shadcn customization guide.
-
Phase 2 (This week)
- Add contrast checker script + CI job.
- Add ESLint/CI rule to block raw colors.
- Consolidate sidebar tokens if needed.
-
Phase 3 (Later)
- Generate TS types from palettes; reduce duplication.
- Add visual regression tests per palette/mode.
Appendix — Code References
src/styles.css— Tailwind@thememapping and derived status tokens.src/styles/color-themes.generated.css— per-palette CSS vars (light/dark).src/styles/tokens.css— base tokens (radius, spacing, typography, etc.).src/hooks/use-color-theme.ts— palette selection and persistence.src/routes/__root.tsx—ThemeProviderwrapper for dark mode.src/components/ui/button.tsx— shadcn/cva usage with semantic utilities.