Make WordPress Core

Opened 7 weeks ago

#64939 new enhancement

Add opt-out mechanism for global admin CSS on individual elements

Reported by: 0mirka00's profile 0mirka00 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version:
Component: General Keywords:
Focuses: Cc:

Description

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:

/* 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 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])):

/* 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.

Change History (0)

Note: See TracTickets for help on using tickets.