Problem/Motivation

"Theming": some design systems have CSS switching like light/dark theme, accessibility modes, or different tones and branding. Most of the time, the theme can be defined with a class in the HTML or BODY element (ex: Tailwind) and the theme is applied to the current element and its children.

However, it can be more complicated:

Proposed resolution

Use this issue to propose a YAML structure for plugin declarations taking into account this complexity.

Issue fork ui_skins-3335428

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

pdureau created an issue. See original summary.

pdureau’s picture

Issue summary: View changes
g4mbini’s picture

Issue summary: View changes
duaelfr’s picture

Maybe I'm missing something but why do you care about how each Design System manages its variants?
The core need is to have more than one preset of CSS vars and to be able to switch from one to another.

  • If this switch has to be done by admins in appearance it's only a matter of configuration.
    In this case, it would be really nice to be able to select a preset then override some values for the current project.
  • If you want to have some kind of switcher in the UI for end users, you can do this the way you want as long as it works in the end.
    In this case it might be interesting to restrict the list of available presets.

My 2 cts

pdureau’s picture

Hello Duaelfr

Maybe I'm missing something but why do you care about how each Design System manages its variants?

"Themes" (or "Modes") are often a "first class" artifacts in design system, they have a name, a documentation, a purpose, and a lifecycle. So, it will convenient to manipulate them as "first class" obejcts too.

The core need is to have more than one preset of CSS vars and to be able to switch from one to another.

Not every design systems design its themes as combinations of CSS vars. Some design systems have themes but no CSS variables. Some design have both, but they are not related.

pdureau’s picture

pdureau’s picture

We need the usual metadata:

  • id, string : Machine name, unique and persistent
  • label, string : Human-friendly, preferably short, name
  • description, string : Human-friendly, more lengthy, explanation
  • status, string : Its stage in a lifecycle: Incomplete, Draft, Published, Obsolete... No processing is made on this value.

And properties specific to theme processing:

Attachment value (string, free text)

The keyword which will be attached (as a class name or a data attribute value). If empty, it is the plugin ID, with Html:::getClass() applied.

Attachment method (string, free text)

2 values:

  • If empty, the value will be merged into an HTML class attributes
  • If value, this will be the HTML attribute name (it will often be a data-* attribute, but not always)

Examples:

  • HTML data attribute : DSFR, Bootsrap4
  • HTML class: Mozilla Protocol

Attachment target (string, enum)

3 values:

  • Empty: the theme (class or data attribute) is scopable, so it can be processed in 2 different ways:
    • If selected from Drupal theme settings page, it will be added (as a class or a data attribute) to the HTML body element.
    • It will also be possible to add it to any element of the page, like the styles from UI Styles.
  • "html": the theme (class or data attribute) will be added to the HTML root element
  • 'body" the theme (class or data attribute) will be added to the HTML body element

Examples:

  • Empty (so "scopable"): Bootstrap 5, Mozilla Protocol
  • "html": DSFR

Asset library

A single assets library definition, which will be loaded if the theme is called in a render request.

Examples: Europa

pdureau’s picture

Example for Bootstrap 5.3:

id: dark
label: Dark
description: ...
# No value because same as plugin ID
method: "data-bs-theme"
# No target because scopable
id: light
label: Light
description: ...
# No value because same as plugin ID
method: "data-bs-theme"
# No target because scopable

Example for Mozilla Protocol:

id: dark
label: Dark
description: ...
value: "mzp-t-dark"
# No method because class name
# No target because scopable

Example for Ant Design:

id: dark
label: "Dark"
library:
  css:
   "dist/antd.dark.min.css": {}
id: compact
label: "Compact"
library:
  css:
   "dist/antd.compact.min.css": {}
pdureau’s picture

Assigned: pdureau » grimreaper
pdureau’s picture

Vocabulary:

grimreaper’s picture

Assigned: grimreaper » Unassigned

- New plugin type
- new plugin definition class
- Alter theme setting form to add theme selector
- Implements hook_preprocess_html to add either in html_attributes or attributes the class or attribute
- Implements tests

- For scopable themes, how to be able to select the theme anywhere?

seda12’s picture

Assigned: Unassigned » seda12
Status: Active » Needs work
grimreaper’s picture

Update about libraries.

Example for Ant Design:

id: dark
label: "Dark"
library: "namespace/my_library"
id: compact
label: "Compact"
library: "namespace/my_other_library"

We do not care how the libraries are declared. We simply add it when the mode is selected.

seda12’s picture

Assigned: seda12 » Unassigned
Status: Needs work » Needs review
grimreaper’s picture

No "Theme mode" => "theme"

grimreaper’s picture

Assigned: Unassigned » grimreaper
grimreaper’s picture

Assigned: grimreaper » Unassigned
Status: Needs review » Needs work
seda12’s picture

Assigned: Unassigned » seda12
seda12’s picture

Assigned: seda12 » Unassigned
Status: Needs work » Needs review
grimreaper’s picture

Assigned: Unassigned » grimreaper
pdureau’s picture

Thanks for your work.

Tested on DSFR:

system:
  label: "System"
  method: data-fr-scheme
  target: html
  
light:
  label: "Light"
  method: data-fr-scheme
  target: html
  
dark:
  label: "Dark"
  method: data-fr-scheme
  target: html

It was working well at the end but I got one fatal error:

TypeError: array_keys(): Argument #1 ($array) must be of type array, null given in array_keys() (line 75 of  Drupal\ui_skins\HookHandler\PreprocessHtml                              
Warning: Undefined property: Drupal\Core\Extension\Extension::$base_themes in Drupal\ui_skins\HookHandler\PreprocessHtml->preprocess()                                                                                          

Not related to my tests, but there is an use case not met yet, but we may need to be able to add theme as a meta element. Example: <meta name="theme" content="system">

So, my proposal:

  • Rename "method" property to "key", so we have key value.
  • Don't implement yet "meta" target yet, but don't make it impossible to implement later
target	key	value	result
""	""	bar	<body class="bar">
html	""	bar	<html class="bar">
body	""	bar	<body class="bar">
meta	""	bar	???
""	foo	bar	<body foo="bar">
html	foo	bar	<html foo="bar">
body	foo	bar	<body foo="bar">
meta	foo	bar	<meta name="foo" content="bar">
pdureau’s picture

Also, on /admin/appearance/settings/{theme} page, the Themes select list must not be mandatory. The default value must be empty (no theme), and it is possible to select this default empty value.

grimreaper’s picture

Issue tags: +ddd2023

  • Grimreaper committed f63cedf7 on 1.0.x authored by seda12
    Issue #3335428 by seda12, Grimreaper, pdureau: Themes: plugin...
grimreaper’s picture

Assigned: grimreaper » Unassigned
Status: Needs review » Fixed

  • Grimreaper committed b2128d6f on 1.0.x
    Issue #3335428 by Grimreaper: Fix empty CSS file warning
    

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.