```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, and auto, with auto labelled 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

  1. Use the color-scheme preference introduced by #3606655.
  2. Select Light, Dark, or System.
  3. Use a theme or design system that does not represent its color mode with data-color-scheme on the html element.
  4. Observe that the account preference cannot be mapped through a theme-defined Style mode.
  5. Observe that the user/account API and theme implementation must either agree on a hard-coded Drupal attribute or add custom preprocessing.
  6. 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:

  • light
  • dark
  • auto, 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:

  1. When forced colors are active, the user agent's enforced palette takes precedence over author-defined light and dark palettes.
  2. An explicit Drupal choice of Light or Dark takes precedence over ordinary prefers-color-scheme styling.
  3. When the stored value is auto, follow prefers-color-scheme.
  4. 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 auto distinct 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:

&lt;meta name="color-scheme" content="light dark"&gt;

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-contrast is independent of prefers-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: custom must not be treated as equivalent to an author-provided high-contrast theme.
  • forced-colors is a user-agent color transformation, not an author theme or another Style mode.
  • forced-color-adjust: none should be reserved for narrowly justified and separately tested cases.
  • prefers-reduced-motion and prefers-reduced-transparency should 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, and auto.
  • auto remains distinct from the currently resolved Light or Dark presentation.
  • A theme can represent auto without being required to emit a literal auto attribute 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-scheme on 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-contrast does not select or replace the color scheme.
  • The bridge does not globally emit color-scheme metadata or set browser color-scheme behavior.
  • 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 auto is 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;
    • auto without server-side resolution;
    • at least two theme-specific mappings;
    • an auto mapping 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, and custom where 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, or auto.
  • System: The user-facing label for the stored auto value.
  • 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 auto option 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:

```

Comments

mgifford created an issue. See original summary.

mgifford’s picture

Issue summary: View changes
mgifford’s picture

Issue summary: View changes
pdureau’s picture

Status: Active » Closed (outdated)

Thanks @mgifford. Duplicate of #3613964: Use Style API to manage dark mode in themes and user settings. Let's continue the discussion there.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

pdureau’s picture

Status: Closed (outdated) » Closed (duplicate)