[wp-trac] [WordPress Trac] #64939: Add opt-out mechanism for global admin CSS on individual elements

WordPress Trac noreply at wordpress.org
Tue Mar 24 13:54:09 UTC 2026


#64939: Add opt-out mechanism for global admin CSS on individual elements
-------------------------+-----------------------------
 Reporter:  0mirka00     |      Owner:  (none)
     Type:  enhancement  |     Status:  new
 Priority:  normal       |  Milestone:  Awaiting Review
Component:  General      |    Version:
 Severity:  normal       |   Keywords:
  Focuses:               |
-------------------------+-----------------------------
 == Problem

 WordPress admin stylesheets (`forms.css`, `common.css`) apply broad, bare-
 element selectors that set visual properties on elements like `input`,
 `textarea`, `button`, `a`, `div`, `p`, and headings. For example:

 {{{#!css
 /* forms.css */
 input[type="text"] { border: 1px solid #949494; min-height: 40px; /* ...
 */ }

 /* common.css */
 a, div { outline: 0; }
 p { font-size: 13px; line-height: 1.5; margin: 1em 0; }
 }}}

 These rules work well for traditional wp-admin screens, but they conflict
 with component libraries that manage their own element styles —
 particularly those using CSS cascade layers, where unlayered admin styles
 unconditionally win regardless of specificity.

 This has been causing inconveniences for years, but is now becoming a
 blocker for adopting modern CSS architectures like `@layer`. We have an
 [https://github.com/WordPress/gutenberg/pull/76783 interim workaround] in
 place for the `@wordpress/ui` package, but a Core-level solution would
 benefit the broader ecosystem: any plugin or component library using
 layered CSS, or simply wanting a clean styling baseline for its UI, faces
 the same problem.

 == Proposal

 Add a `data-wp-no-global-css` attribute that opts individual elements out
 of admin global styles. Each bare element selector in `forms.css` and
 `common.css` would be guarded with `:where(:not([data-wp-no-global-
 css]))`:


 {{{#!css
 /* Before */
 input,
 select,
 textarea,
 button {
   box-sizing: border-box;
   font-family: inherit;
   font-size: inherit;
   font-weight: inherit;
 }

 /* After */
 :is(input, select, textarea, button):where(:not([data-wp-no-global-css]))
 {
   box-sizing: border-box;
   font-family: inherit;
   font-size: inherit;
   font-weight: inherit;
 }
 }}}


 An element with the attribute is simply excluded from the rule. Elements
 without it are unaffected.

 === Design goals

 - **Specificity-neutral** — `:where()` adds zero specificity, so existing
 overrides of admin styles continue to work.
 - **Per-element** — the guard is on each element selector, not an ancestor
 wrapper, so there's no gap where the wrapper itself still receives admin
 styles.
 - **Package-agnostic** — usable by `@wordpress/components`,
 `@wordpress/ui`, or any third-party component library.
 - **Not a styling hook** — the attribute name describes an opt-out
 behavior, not a component identity, so it doesn't invite misuse as a
 selector by consumers.
 - **Backwards compatible** — the default behavior (no attribute) is
 identical to today.

 === Scope

 Only the bare/unscoped element selectors in `forms.css` and `common.css`
 need the guard — roughly the first ~335 lines of `forms.css` and the
 element resets in `common.css`. Class-scoped rules (`.wp-admin ...`,
 `.form-table ...`, etc.) are already sufficiently scoped and don't need
 changes.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/64939>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list