Opened 3 months ago
Closed 3 months ago
#65443 closed enhancement (duplicate)
Replace hardcoded admin CSS colors with centralized CSS custom properties
| Reported by: | dervishov | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | |
| Component: | Administration | Version: | |
| Severity: | normal | Keywords: | has-patch |
| Cc: | Focuses: |
Description (last modified by )
I've been digging into how WordPress admin handles colors and noticed something that's been bugging me for a while — there are over 740 hardcoded hex values scattered across 14 CSS files (common.css, forms.css, dashboard.css, list-tables.css, etc.), and the color scheme system can only touch the sidebar and admin bar. The actual content area — page backgrounds, card surfaces, text, borders, form inputs, table rows, notices — is completely locked to static hex values.
This means if you want to build a dark mode, a high-contrast mode, or even just let an agency brand the admin panel beyond the sidebar, you're stuck writing hundreds of selector-level overrides. I tried building a dark scheme and ended up with 390 lines of CSS just to flip the content area colors. That's not sustainable.
So I went ahead and built what I think is a cleaner foundation: a set of 32 semantic CSS custom properties defined in a single :root{} block at the top of common.css. Then I went through all 14 admin CSS files and replaced the hardcoded hex values with var() references.
The property set breaks down like this:
- Backgrounds —
--wp-admin-bg-page(#f0f0f1),--wp-admin-bg-card(#fff),--wp-admin-bg-alt(#f6f7f7),--wp-admin-bg-hover,--wp-admin-bg-disabled - Text —
--wp-admin-text-primary(#1d2327),--wp-admin-text-body(#3c434a),--wp-admin-text-secondary(#646970),--wp-admin-text-tertiary(#50575e),--wp-admin-text-placeholder(#a7aaad),--wp-admin-text-inverse(#fff) - Borders —
--wp-admin-border-default(#c3c4c7),--wp-admin-border-light(#dcdcde),--wp-admin-border-emphasis(#2c3338),--wp-admin-border-subtle(#8c8f94) - Status — error, warning, success, info — each with a foreground color, background tint, and border accent (10 properties total)
- Shadows —
--wp-admin-shadow-color,--wp-admin-overlay-dark
Every default value matches the existing hardcoded hex exactly, so there's zero visual change for any current color scheme. Modern, Midnight, Coffee — they all render identically. The only difference is that now, overriding 32 variables in a color scheme stylesheet is enough to re-skin the entire admin.
To give a concrete example: a dark mode that previously required 390 lines of .admin-color-dark .postbox, .admin-color-dark input[type="text"], .admin-color-dark .widefat td... can now be done in about 35 lines of variable reassignment. Same story for high contrast, reduced motion themes, or agency whitelabel setups.
I intentionally kept this to 32 properties because I wanted to hit the sweet spot — enough to cover 86% of all color instances without creating a maintenance burden. The remaining 14% are mostly theme-color-dependent values already handled by --wp-admin-theme-color, or one-off colors in niche contexts.
A few things I'd love feedback on:
- Are the property names clear enough? I went with semantic names like
--wp-admin-text-secondaryinstead of palette-based names like--wp-admin-gray-646970, but I know there are different schools of thought here. - Should the
:root{}block live incommon.css(as I've done), or would a dedicated file be better? - Is 32 the right number? I could expand to ~40 to capture more edge cases, or trim to ~25 by merging some status variants.
GitHub PR with the full implementation: https://github.com/WordPress/wordpress-develop/pull/12133
Happy to iterate based on feedback from the CSS and design folks.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
## Summary
Replace 740+ hardcoded hex color values across 14 admin CSS files with references to 32 semantic CSS custom properties defined in a single
:root{}block incommon.css.## Problem
WordPress admin uses hardcoded hex colors scattered across
common.css,forms.css,dashboard.css,list-tables.css,edit.css,themes.css,media.css,widgets.css,nav-menus.css,admin-menu.css,customize-controls.css,revisions.css,about.css, andsite-health.css. Color schemes can only change the admin menu/bar/buttons — the content area is locked to static values.## Solution
Define 32 semantic CSS custom properties in
common.css :root{}, then replace hardcoded values withvar()references.Backgrounds (5):
--wp-admin-bg-page,--wp-admin-bg-card,--wp-admin-bg-alt,--wp-admin-bg-hover,--wp-admin-bg-disabledText (6):
--wp-admin-text-primary,--wp-admin-text-body,--wp-admin-text-secondary,--wp-admin-text-tertiary,--wp-admin-text-placeholder,--wp-admin-text-inverseBorders (4):
--wp-admin-border-default,--wp-admin-border-light,--wp-admin-border-emphasis,--wp-admin-border-subtleStatus (10): error, warning, success — each with color + background + border variants
Info/Links (2), Shadows (2), Extremes (1)
## Key design decisions
--wp-admin-text-secondarynot--wp-admin-gray-646970)## What this unlocks
wp_add_inline_stylevar(--wp-admin-bg-card)works in any admin context## Files changed
src/wp-admin/css/common.css—:root{}block + var() replacementssrc/wp-admin/css/forms.css— var() replacementssrc/wp-admin/css/dashboard.css— var() replacementssrc/wp-admin/css/list-tables.css— var() replacementssrc/wp-admin/css/edit.css— var() replacementssrc/wp-admin/css/themes.css— var() replacementssrc/wp-admin/css/media.css— var() replacementssrc/wp-admin/css/widgets.css— var() replacementssrc/wp-admin/css/nav-menus.css— var() replacementssrc/wp-admin/css/admin-menu.css— var() replacementssrc/wp-admin/css/customize-controls.css— var() replacementssrc/wp-admin/css/revisions.css— var() replacementssrc/wp-admin/css/about.css— var() replacementssrc/wp-admin/css/site-health.css— var() replacements## Test plan
npm run build:devbuilds successfully:rootbody { --wp-admin-bg-card: red; }turns all card backgrounds red