Skip to content

UI Skins

Philosophy: Expose CSS custom properties (design tokens) and theme variants as YAML plugins so site builders can pick brand colors, modes, and theme switches from theme settings — without forking the theme. Skins inject CSS variables and class/data attributes into the page head and root element at render time.

I need to... Guide Summary
Understand what UI Skins does and when to use it Overview Use UI Skins when site builders need to adjust CSS custom property values (colors, tokens) or toggle named theme variants (light/dark/brand) from theme settings. It is config-time and theme-wide — not per-block and not runtime.
Install UI Skins Installation Install UI Skins with composer and drush en. Single module only — no submodules exist. Requires Drupal ^11.4 || ^12 and PHP 8.3+. Once enabled, it adds CSS variable and theme controls to every theme's settings form.
Declare a CSS variable plugin in YAML CSS Variable Definition Declare CSS variable plugins in {theme}.ui_skins.css_variables.yml at the theme root. Each plugin maps a machine name to a CSS variable, a form widget type, a label, and a map of CSS scope → default value. Plugin ID becomes the CSS variable name with -- prefix.
Pick a form widget for a CSS variable Variable Types & Widgets Use ui_skins_alpha_color for color tokens (stores 8-char hex with alpha), textfield for numeric/unit/arbitrary CSS values, or a custom form element plugin for specialized inputs. Mixing up type and value format silently breaks CSS.
Wire variable scopes for nested overrides Variable Scopes default_values is a map of CSS selector → value. Multiple scopes emit separate CSS rules at render time, letting the cascade deliver the right default in different contexts (:root, .theme-dark, .callout-warning). Site-builder edits only replace the :root scope value.
Declare a theme plugin (light/dark/brand variant) Theme Definition Declare theme plugins in {theme}.ui_skins.themes.yml at the theme root. Each plugin specifies a target element (body or html), injection key (class or data-attribute), value, optional asset library, and optional dependencies. Site builder picks one; UI Skins injects the class or attribute at render time.
Apply a class vs a data attribute for theme switches Theme Targets & Keys Match target and key to the CSS selectors your theme already uses. Bootstrap 5 uses html[data-bs-theme]; Tailwind dark mode uses html.dark; DaisyUI uses html[data-theme]. A mismatch between target and CSS selectors means nothing applies.
Chain themes via dependencies Theme Dependencies Theme dependencies are additive — declaring one theme as a dependency of another causes both to activate simultaneously, producing multiple classes on the target element. They are not a mutual-exclusivity mechanism; separate plugin IDs handle that.
Ship a sub-theme with its own variables and themes Theme Authoring Author CSS using var(--token), attach it via libraries.yml, declare matching plugins in {theme}.ui_skins.css_variables.yml and {theme}.ui_skins.themes.yml at the theme root, then clear cache. Both YAML files must be at the theme root — subdirectories are not scanned. Sub-themes inherit parent plugin definitions and can override with the same plugin ID.
Understand the render-time injection mechanism Render Pipeline UI Skins splits its render-time work across two #[Hook]-attributed classes (no .module file): Hook\PreprocessHtml injects body/html class or data attributes and attaches libraries, Hook\PageTop emits a <style> tag into page top. Both read settings via ThemeSettingsProvider::getSetting(), not theme_get_setting(); flat ui_skins_css_variables:/ui_skins_theme: config keys are legacy and silently produce nothing.
Combine UI Skins with UI Styles UI Skins + UI Styles Together UI Skins and UI Styles are orthogonal. UI Skins controls the value of CSS variables (theme-wide), UI Styles controls which utility classes are applied to individual blocks. The pattern is: UI Skins sets --brand-primary, UI Styles applies text-primary to a block, CSS links them via var(--brand-primary).
Avoid common mistakes Anti-Patterns The most common mistakes are hardcoding hex colors in CSS files instead of declaring UI Skins variables, expecting runtime user-facing theme switching from a config-time module, and placing YAML files in theme subdirectories instead of the theme root.
Find key classes and services Code Reference Map UI Skins ships two plugin managers (CssVariablePluginManager, ThemePluginManager), two #[Hook]-attributed classes under src/Hook/ (PreprocessHtml, PageTop — no .module file), and stores its settings nested under third_party_settings.ui_skins.* per the keys on UiSkinsInterface. Plugin YAML files must live at the theme/module root.