```html
Problem/Motivation
This is a follow-up to:
Drupal needs to treat light and dark color schemes as a first-class user preference rather than as a setting owned by one theme.
#3606655 establishes the user-facing part of this:
- a central per-user color-scheme preference;
- canonical values of
light,dark, andauto, withautolabelled System; - account storage and access;
- cacheability;
- consistent availability across front-end and administrative contexts; and
- a theme capability declaration.
#3517033 establishes the presentation mechanism:
- themes and modules can declare named style modes;
- a mode can map an abstract option to a class, attribute, target element, metadata value, and library;
- global modes can be applied to
html,body, or page metadata; and - the implementation is not limited to Drupal-specific class or attribute conventions.
The two APIs solve different parts of the same problem, but there is no defined bridge between them.
Without that bridge, Drupal's central preference remains tied to a specific representation such as:
<html data-color-scheme="dark">
That representation may work for one Drupal theme, but other themes and design systems may require:
<html data-theme="dark">
<html data-bs-theme="dark">
<html data-fr-scheme="dark">
<html class="theme-dark">Some design systems apply the marker to body or another container instead of html. Some use no explicit marker for System mode and rely on prefers-color-scheme.
The account API should not need to know these theme-specific details. It should expose the user's canonical preference, while the theme defines how that preference is represented.
This issue connects the first-class Drupal color-scheme preference to the Style Utility API.
First-class support does not mean that every Drupal theme automatically gains an accessible dark palette. A theme must deliberately implement, test, and declare support for every color scheme it provides.
Steps to reproduce
- Use the color-scheme preference introduced by #3606655.
- Select Light, Dark, or System.
- Use a theme or design system that does not represent its color mode with
data-color-schemeon thehtmlelement. - Observe that the account preference cannot be mapped through a theme-defined Style mode.
- Observe that the user/account API and theme implementation must either agree on a hard-coded Drupal attribute or add custom preprocessing.
- Select System and observe that the Style Utility API has no defined way to represent an option that may intentionally emit no class or attribute.
Proposed resolution
Define and implement a design-system-neutral bridge between Drupal's canonical color-scheme preference and a Style mode declared by a supporting theme.
Use a canonical preference
Continue using the canonical values established by #3606655:
lightdarkauto, labelled System in the user interface
The user/account API exposes only this canonical preference. It must not expose a design-system-specific class, attribute, selector, target, or library.
Associate the preference with a Style mode
Provide a way for a supporting theme to associate Drupal's color-scheme preference with a mode declared through the Style Utility API.
The theme's style definition controls:
- the class or attribute used by its design system;
- the value associated with each option;
- the target element;
- any associated library; and
- other design-system-specific representation details.
The exact API for declaring this association still requires agreement. It must not hard-code data-color-scheme into the account API or make the Style API dependent on one theme implementation.
The association mechanism should be reusable for a future persisted presentation preference, but this issue implements only color scheme.
Separate the selected preference from the resolved presentation
The stored preference and the presentation eventually resolved by the browser or theme are different concepts.
For example:
- selected preference:
auto; - current operating-system preference: Dark; and
- resolved presentation: Dark.
Drupal must keep the stored value as auto. It must not replace it with the currently detected operating-system value.
A theme must be able to represent auto by:
- emitting no explicit class or attribute and following
prefers-color-scheme; - emitting a design-system-specific automatic value; or
- using client-side resolution when its design system cannot follow the media query directly.
The Style Utility API may need to support an option that deliberately emits no local attribute. Alternatively, the integration may apply a Style mode only for explicit light and dark choices. This must be decided in this issue.
A literal attribute such as data-theme="auto" must not be required unless the consuming design system understands that value.
Define preference precedence
Use the following precedence:
- When forced colors are active, the user agent's enforced palette takes precedence over author-defined light and dark palettes.
- An explicit Drupal choice of Light or Dark takes precedence over ordinary
prefers-color-schemestyling. - When the stored value is
auto, followprefers-color-scheme. - Site-wide defaults remain the responsibility of #3618721.
The explicit Drupal preference should be applied at an authoritative page level. A component or nested renderable must not accidentally override the user's global color-scheme preference through a conflicting Style attachment.
Modules providing interface elements within a page, including navigation and administrative chrome, must consume the same canonical preference rather than selecting a global color scheme independently.
Prefer browser resolution for System mode
Drupal must not attempt to resolve prefers-color-scheme on the server. This preference is only available to the browser and cannot be determined reliably from an HTTP request.
CSS media-query resolution is preferred because it:
- responds when the operating-system preference changes;
- avoids unnecessary server-side cache variation;
- works without JavaScript;
- avoids copying system preference information into account data; and
- reduces the risk of an incorrect first-paint theme.
If a theme requires JavaScript to resolve System mode, it must:
- respond when the operating-system preference changes;
- retain an accessible fallback when JavaScript fails;
- avoid blocking rendering while preference code loads;
- avoid an incorrect initial color scheme where reasonably possible; and
- keep
autodistinct from the resolved Light or Dark presentation.
System preference values must not be stored in the user account, exposed in public profiles, or transmitted to analytics merely because they can be detected.
Leave browser UI integration to themes
This integration must not globally emit:
<meta name="color-scheme" content="light dark">It must also not globally set the CSS color-scheme property.
These declarations affect browser-provided controls, scrollbars, form surfaces, and other user-agent rendering. They remain the responsibility of a theme that has implemented and tested the relevant schemes.
Define the meaning of theme support
A theme should declare color-scheme support only when it provides a complete, maintained implementation.
Theme support includes consideration of:
- text and non-text contrast;
- focus, hover, active, selected, checked, expanded, current, disabled, error, autofill, and visited-link states;
- forms and browser-provided controls;
- icons, charts, maps, syntax highlighting, transparent images, and embedded content;
- forced-colors behavior;
- text resizing, zoom, reflow, and text-spacing overrides;
- long translations, bidirectional content, complex scripts, and combining characters; and
- print output.
The capability declaration is a contract made by the theme. Drupal cannot automatically prove that every palette and component state is accessible.
Define boundaries with other user preferences
This issue defines how related user preference signals interact with color scheme, but it does not implement them as stored Drupal preferences.
prefers-contrastis independent ofprefers-color-scheme. It must not automatically select Light or Dark.- A request for less contrast must not reduce content or controls below applicable accessibility requirements.
prefers-contrast: custommust not be treated as equivalent to an author-provided high-contrast theme.forced-colorsis a user-agent color transformation, not an author theme or another Style mode.forced-color-adjust: noneshould be reserved for narrowly justified and separately tested cases.prefers-reduced-motionandprefers-reduced-transparencyshould normally remain CSS media-query responses.- Theme changes should not be animated by default. Any optional transitions must respect
prefers-reduced-motion.
Acceptance criteria
- A supporting theme can associate Drupal's canonical color-scheme preference with a declared Style mode.
- The account API does not expose theme-specific classes, attributes, targets, or selectors.
- The canonical stored values remain
light,dark, andauto. autoremains distinct from the currently resolved Light or Dark presentation.- A theme can represent
autowithout being required to emit a literalautoattribute value. - A theme can choose its own class or attribute, values, target, and library.
- An explicit Dark choice works when the operating system prefers Light.
- An explicit Light choice works when the operating system prefers Dark.
- System follows
prefers-color-scheme, including changes made while the page is open. - Drupal does not resolve
prefers-color-schemeon the server. - System preference values are not copied into account data or analytics.
- Forced colors take precedence over author palettes without changing the stored Drupal selection.
prefers-contrastdoes not select or replace the color scheme.- The bridge does not globally emit color-scheme metadata or set browser
color-schemebehavior. - Missing or invalid preference data falls back safely to
auto. - Themes without declared support receive no unnecessary output or cache variation.
- Front-end, administrative, and module-provided interface elements use the same canonical preference when rendered together.
- Nested Style attachments cannot accidentally override the user's authoritative page-level preference.
- The implementation remains usable when JavaScript is unavailable.
- Preference and Style attachment precedence are documented.
Out of scope
- Creating another color-scheme field or preference interface.
- Implementing dark-mode CSS for individual themes.
- Adding an anonymous-user theme selector.
- Adding stored contrast, motion, transparency, text-size, density, font, or reading-layout preferences.
- Resolving the operating-system preference on the server.
- Requiring JavaScript for themes that can use CSS media queries.
- Globally emitting
<meta name="color-scheme">. - Implementing the Design Tokens API.
- Treating forced colors as an author-defined high-contrast theme.
- Treating a theme capability declaration as proof of WCAG conformance.
- Guaranteeing that arbitrary theme palettes meet accessibility requirements.
- Animating color-scheme changes.
Remaining tasks
- Agree on how a preference identifies or invokes a Style mode.
- Decide how
autois represented when a theme requires no output. - Confirm how the authoritative user preference interacts with Style attachment precedence.
- Implement the bridge after #3606655 and #3517033 provide the underlying APIs.
- Add automated tests for:
- missing and invalid preference values;
- explicit Light with a Dark system preference;
- explicit Dark with a Light system preference;
autowithout server-side resolution;- at least two theme-specific mappings;
- an
automapping that emits no explicit theme attribute; - a theme without color-scheme support;
- consistent preference handling across front-end and administrative rendering;
- precedence over conflicting nested Style attachments;
- cacheability metadata; and
- the absence of design-system-specific values from the account API.
- Add browser-level or documented manual tests for:
- changing the operating-system preference while System is selected;
- an incorrect first-paint theme;
- unavailable JavaScript where client-side resolution is used;
- forced colors with each stored color-scheme value;
prefers-contrast: more,less, andcustomwhere supported;- focus, hover, selected, disabled, error, autofill, and visited-link states;
- images, graphics, tables, code, transparent assets, and embedded content;
- 200% text resizing, 400% page zoom, reflow, and text-spacing overrides;
- representative complex scripts and combining characters; and
- print output.
- Document responsibilities for Drupal core, modules, and themes.
- Add a change record if a public API is introduced.
User interface changes
None.
The color-scheme control, labels, descriptions, and account editing interface belong to #3606655.
Introduced terminology
- Color scheme: The presentation family commonly described as Light or Dark.
- Selected preference: The canonical value intentionally stored by Drupal:
light,dark, orauto. - System: The user-facing label for the stored
autovalue. - Resolved presentation: The Light or Dark presentation eventually selected by an explicit preference, CSS media query, or theme integration.
- Theme capability: A declaration that a theme has implemented and intends to support the complete color-scheme behavior.
- Forced colors: A user-agent mode that enforces a user-selected system palette. It is not an author-defined high-contrast theme.
API changes
To be determined.
The expected API addition is a design-system-neutral association between a canonical user preference and a theme-defined Style mode.
The API must:
- keep account preferences independent of theme-specific output;
- allow themes to map canonical options to their own classes, attributes, targets, and libraries;
- support an
autooption that may intentionally emit no local attribute; - preserve theme capability and cacheability requirements; and
- prevent nested Style attachments from unintentionally overriding the authoritative user preference.
Data model changes
None.
The user color-scheme preference and its canonical values are provided by #3606655.
Release notes snippet
Drupal now treats light and dark color schemes as a first-class user preference that can be implemented consistently across front-end and administrative themes.
The canonical Light, Dark, and System preference can be associated with a theme-defined Style mode. Themes can map the preference to the classes, data attributes, target elements, and libraries required by their design system without exposing those implementation details through the user account API.
System mode follows the user's operating-system or browser preference, while explicit Light and Dark choices override ordinary color-scheme detection. Themes continue to control their own palettes and browser color-scheme integration.
Related issues and references:
- #3517033: Add a style utility API
- #3606655: Make dark mode a first class citizen of Drupal core
- #3413207: META: Provide better support for color and contrast media queries
- #3531854: Add a Design Tokens & CSS variables API
- #3618721: Consider allowing site admins to set global values for light/dark mode
- User Personalization and Accessibility Best Practices
- Light/Dark Mode Accessibility Best Practices
- Media Queries Level 5
- CSS Color Adjustment Module Level 1
```
Comments
Comment #2
mgiffordComment #3
mgiffordComment #4
mgiffordComment #5
kentr commentedThis is related: #3613964: Use Style API to manage dark mode in themes and user settings
Comment #6
pdureau commentedThanks @mgifford. Duplicate of #3613964: Use Style API to manage dark mode in themes and user settings. Let's continue the discussion there.
Comment #8
pdureau commented