Standardized Design Tokens and CSS for a consistent, customizable, and interoperable WordPress future

This is a proposal to use CSS utility classes for common layout needs and access to site-specific standardized design tokens set in theme.json. Doing so will allow WordPress “core”, themes, and plugins to have access to a valuable shared CSS toolkit. The result is a WordPress landscape where WordPress markup and styles are easier to extend, site content is more portable, and themes and plugins are more interoperable.

March 4, 2022: Thanks to everyone who read this and up-voted the Github issue or left a comment here or on WP Tavern! (Keep it up!) The response has been amazing. In light of some of the great comments and feedback this has received, I added a new appendix at the end with a few clarifying points.

April 15, 2022: It’s been wonderful to see the discussion of these issues picking up steam! This week, a new article “Core Styles and Theme Customization: the next steps” was posted on the Make WordPress Core blog about moving these efforts forward. What’s most important is that there are new standards and clearer communication of them, not that the specific implementations I propose here are adopted. If you want to get involved in this discussion, read that post and then leave comments on the linked Github issues.

How we got here

The new WordPress Full Site Editing (FSE) feature takes the concepts of the block editor and brings them to the entire site. It is clear that in the near future it will be possible to build beautiful, custom WordPress websites with little-to-no code.

Even once that is possible, many sites will always have the need for advanced customizations and functions beyond the capabilities of FSE in order to faithfully implement their brands or create unique features or designs. This is the world I work in and the perspective I bring.

I would like to propose a path toward standardizing how CSS for WordPress designs and layouts are created so they are more transparent, efficient, and customizable. Not only can this approach simplify core styles, it would address a number of long-term WordPress pain points that predate even the block editor’s release in WordPress 5.0.

None of these ideas are new! In fact, most are already half-implemented in one way or another and have already been suggested by other people. The primary changes required by this proposal are mostly about defining standards and committing to developing with some shared code and vision.

Every idea below stands on the shoulders of other WordPress community members who have written blog posts or I’ve talked with about these issues.

To acknowledge just a few of the posts and people that have influenced this one at a high level:

I’m particularly grateful to Aurooba Ahmed, Patty O’Hara, and Hendrik Luehrsen, for reviewing this post and providing helpful feedback! Thanks also to Anne McCarthy and Birgit Pauli-Haack for guidance on publishing this post.

“The Block-Theme Contract”

It is clear that WordPress can provide a significant portion of front-end markup and styling responsibility, but this won’t serve the community if the result is a “walled garden”. Recent changes to WordPress 5.9 appear headed in a direction where website styling outside of the WordPress-provided interface becomes more complicated and less reliable for people customizing front-end markup and styles.

It’s been over three years since the block editor was released, yet theme authors are still unclear about what they can rely on in the block editor (credit to Luis Herranz for the “block-theme contract” phrase). Even among early and excited adopters of the block editor, I still frequently hear concerns and frustration from people who write custom themes and plugins about the lack of a consistent, and extensible front-end approach for blocks and their styles, much less a roadmap for this set of needs.

(The existence of this post further highlights the need for more public plans and standards where people can weigh in. There isn’t a single obvious discussion, blog post, or Github issue where I could publish this in response.)

Recent issues make the need for a consistent transparent approach clear:

Now is a critical moment to find a path that meets the needs of WordPress core development without sacrificing the needs of 3rd-party themes and plugins. In finding a forward path, we can unlock new and exciting possibilities for core, themes, and plugins that strengthen the entire WordPress ecosystem.

Semantic and relative values will save our future selves

A major issue I observe in the current interface and rarely see acknowledged is the downside of using specific numerical values as the primary way to customize blocks in post content. This includes things like the ability to define a single paragraph’s font size, column’s gap, or group’s top/right/bottom/left padding in px or em as opposed to a semantic values like “Large” or “+2”.

Individual values are hard for users to keep consistent from page to page, won’t necessarily make sense in the context of a new theme, and generally encourage tinkering. Semantic values, on the other hand, promote consistency and are absolutely good enough for the 80% of situations core WordPress should strive to support. Most importantly, a limited number of semantic values can be defined by themes so they are cohesive but still honor user decisions.

This proposal supposes that blocks should primarily use settings that let editors select preset values on a scale for sizing options in addition to the existing ability to define one-off absolute values. This will result in DRYer (“Don’t Repeat Yourself”) code and user settings/options

The value of constrained options is significant and varied across user groups. Many enterprise-level sites need more consistency to enforce brand standards, but first-time do-it-yourself users will also benefit from constrained choices that still enable sufficient control.

To give a specific example, a 2rem margin could look too small in one theme and too big in another. But a margin that is “Large” relative to the theme’s baseline white space will always look large in the context of a site. Absolute values have their place in “art directed” posts or when dealing with unusual content, but we will do our future selves a huge favor if we focus the editor experience on creating portable content that can move from one design to another.

Four-point plan: Consistent CSS classes, stateful CSS classes, design tokens, and CSS utility classes

This proposal outlines how WordPress could provide all the common markup and styles required for a basic website’s needs (the goal of FSE) while enabling themes and plugins to extend styles for more complicated design and layouts.

The intention is to provide standards for all common needs (the 20% of features required to support 80% of use cases). The goal of these recommendations is NOT to force anyone to write their code in a certain way. The result would provide a set of optional tools that we can all use together to build leaner, consistent, flexible websites.

While some of these ideas would represent a change in how styles are output and managed in WordPress, this proposal is about fully embracing and extending existing practices in the block editor and modern theme design.

There are four key parts of the proposal, all of which have current precedent in WordPress:

  1. Ensuring every HTML element in complex core blocks has a unique class and use single-class selectors in core CSS
  2. Communicating the full state of each block with CSS classes on the block wrapper element
  3. Standardizing theme.json design token naming conventions and increasing the use of settings that use presets instead of absolute values
  4. Creating a set of global, WordPress CSS utility classes intended for use by core blocks, themes, and plugins

I believe this proposal is achievable in 1 or 2 WordPress release cycles starting with WordPress 6.1. Each part of the proposal is made more useful by the other three, but these could be developed and released one- or two-at-a-time in the listed order.

An example of the proposal in code

theme.json with standardized naming schemes and scales (using color palette and gap as examples):

{
    "version": 2,
    "$schema": "https://schemas.wp.org/trunk/theme.json",
    "settings": {
        "color": {
            "palette": [
                {
                    "slug": "background",
                    "color": "#ffefd5",
                    "name": "Papaya Whip"
                },
                {
                    "slug": "foreground",
                    "color": "#000000",
                    "name": "Black"
                },
                {
                    "slug": "primary",
                    "color": "#800000",
                    "name": "Maroon"
                },
                {
                    "slug": "secondary",
                    "color": "#4b0082",
                    "name": "Indigo"
                },
                {
                    "slug": "accent",
                    "color": "#7cfc00",
                    "name": "Lawn Green"
                },
            ]
        }
    },
    "styles": {
        "spacing": {
            "gap": {
                {
                    "slug": "1",
                    "size": ".75rem",
                    "name": "Compact"
                },
                {
                    "slug": "2",
                    "size": "1.75rem",
                    "name": "Narrow"
                },
                {
                    "slug": "3",
                    "size": "2.25rem",
                    "name": "Regular"
                },
                {
                    "slug": "4",
                    "size": "3rem",
                    "name": "Open"
                },
                {
                    "slug": "5",
                    "size": "5rem",
                    "name": "Expansive"
                }
            }
        }
    }
}

Note: The names of the scale could still be entirely up to the theme. The slug is what would be standardized for custom properties and CSS classes.

CSS custom properties and utility classes for implementing design tokens and common layout needs:

:root {
    --wp--preset--color--background: #ffefd5;
    --wp--preset--color--foreground: #000000;
    --wp--preset--color--primary: #800000;
    --wp--preset--color--secondary: #4b0082;
    --wp--preset--color--accent: #7cfc00;
    --wp-gap-1: .75rem;
    --wp-gap-2: 1.75rem;
    --wp-gap-3: 2.25rem;
    --wp-gap-4: 3rem;
    --wp-gap-5: 5rem;
	
    /* etc. */
    --wp-padding-3: 2.25rem;
}
/* Default block styles such as… */
.wp-block-columns {
    display: flex;
    gap: var(--wp-gap-3);
}
.wp-block-column {
	flex: 1 0 0;
}
/* Layout variation utility classes including… */
.wp-align-center {
    align-self: center;
}
.has-background {
    padding: var(--wp-padding-3);
}
/* Colors classes including… */
.wp-color-background {
    color: var(--wp--preset--color--background);
}
.wp-background-color-primary {
    background-color: var(--wp--preset--color--primary);
}
/* .wp-gap-{1-5} including… */
.wp-gap-4 {
    gap: var(--wp-gap-4);
}

Standard HTML markup with lots of descriptive classes for use as theme hooks.

<div class="wp-block-columns has-background has-background-color-primary has-color-background wp-gap-4">
    <div class="wp-block-column"></div>
    <div class="wp-block-column is-vertically-aligned-center wp-align-center"></div>
</div>
All the code together in a CodePen.

Aside: The article “Building a Scalable CSS Architecture With BEM and Utility Classes” argues for many similar ideas and is useful additional reading.

1. Ensuring every HTML element in complex core blocks has a unique class and use single-class selectors in core CSS

One thing this proposal assumes is retaining and embracing a consistent convention for CSS class names on core block HTML markup (excluding p, h1h6, and ul/ol). Every element possible should receive a backwards-compatible class, e.g. wp-block-media-text, wp-block-media-text__content, wp-block-media-text__media, wp-block-media-text__image (that last one would be new!). Core has mostly used the “Block Element Modifier” (BEM) style of classes, so it likely makes sense to continue using that style to avoid breaking changes.

This is for a few key reasons:

  • Allow third-party CSS selectors to style core blocks with confidence
  • Keep selector specificity of core CSS low
  • CSS class selectors allow changing of element types without breaking stylesheets (e.g., changing a div to a figure without having to update a class selector)
  • Block-specific styles can still be contained in rulesets targeting these classes (this is not a proposal to switch to atomic CSS for all styling)

2. Communicating block state with CSS classes

The block editor provides numerous options for alignment, transparency, positioning, and more. Each setting suggests broad user intent, but the precise interpretation of settings can still be controlled by a theme. This is an area where themes can show off their creativity and attention to detail.

The Media & Text block offers a good real-world example. The vertical alignment options normally control only the position of inner blocks but can be customized to control the content box’s position by a creative theme. More simply, a theme author might choose to change the padding of the Media & Text block’s content box depending on whether the has-background class is present (something the paragraph block already does out of the box).

Already, most blocks communicate a significant majority of “state” with classes. So this proposal is limited to fully committing to and extending state-based CSS classes to fully cover all relevant block options. It’s probably too late to standardize the naming scheme of existing classes due to backwards compatibility, but it’s not too late to make sure that a class is always available.

[Some] Existing State Classes

As stated, the state-based CSS classes that exist right now should remain. The ones that have been removed should be added back. Future options that impact front-end markup should be added.

Here’s a list of some of the existing classes:

  • Block Alignment: alignwide and alignfull
  • Text Alignment: has-text-align-{value}
  • Colors:
    • has-{name}-background-color and has-{name}-color
    • has-background-color and has-text-color
  • Font-sizes: has-{name}-font-size
  • Cover Block
    • is-light
    • has-custom-content-position and is-position-{vertical}-{horizontal}
    • has-background-dim and has-background-dim-{opacity}
  • Media & Text
    • has-media-on-the-{left/right}
    • is-stacked-on-mobile
    • is-vertically-aligned-{align}
    • is-image-fill
  • Buttons

3. Standardizing and extending theme.json design tokens

The purpose of theme.json is to manage styles and centralize configuration of values used for site design. This is very similar to the concept of “design tokens” which provides the key inspiration for this proposal overall. By standardizing values in theme.json and the Global Styles panel, WordPress sites can ship with more consistent CSS and less of it (for faster sites)!

Many values in theme.json are already output as custom properties in CSS. What is holding this system back, though, is:

  1. a lack of standard naming conventions
  2. existing and shared CSS classes to apply each property

Adding those two things, would unlock huge opportunities for theme and plugin compatibility.

The following is a list of suggested standard names for design tokens in theme.json. Standardization is more important than using these specific values, but I’ve done my best to provide a starting point that I think could be adopted almost as-is. (See the appendix for some reasoning behind my choices here.)

For all sizes (fonts, margins, gaps, etc.), I recommend using an odd-numbered scale where the central point is the default value. (Or maybe themes could even define where the default is on the scale.) This has a few advantages including fewer naming decisions, easier for non-English speakers, and general clarity. While it would be tempting to provide wider ranges, I think smaller ones covering the 80/20 rule make sense for core-provided tokens and classes.

  • Colors & Gradients
    • foreground, background, primary, secondary, accent
  • Font Sizes
    • font-size-1, font-size-2, font-size-3, font-size-4 (default), font-size-5, font-size-6, font-size-7
  • Font Weights (added based on comment from @cbirdsong)
    • font-weight-1, font-weight-2, font-weight-3 (default), font-weight-4, font-weight-5
  • Font Families
    • copy, headings, monospace
  • Borders
    • border-1, border-2 (default), border-3
  • Gap
    • gap-1, gap-2, gap-3 (default), gap-4, gap-5
  • Margin
    • margin-1, margin-2, margin-3 (default), margin-4, margin-5
  • Padding
    • padding-1, padding-2, padding-3 (default), padding-4, padding-5
  • Media Query Breakpoints*
    • two-columns, three-columns, desktop-menu
  • Content Widths
    • contentSize (exists), wideSize (exists), maxSize (new!)

In the future, this system could be easily extended by, for instance, adding a 5-point border-radius scale for use with buttons and other blocks.

This is far from the first attempt to propose a standard, but this moment calls for one more than ever. Other people agree. Key inspirations for this part of the proposal include:

March 4, 2022: Since originally posting this article, I’ve created a new demo showing how these scales could be implemented in an extremely flexible way where theme authors can choose to use some, all, or parts of the numeric scales:

4. CSS utility classes for each design token and core layout need

Imagine the power of allowing plugins with significant front-end output to automatically use the theme or user-selected values for things like gaps, fonts, padding, colors, and even media queries just by applying standardized classes to their markup!

Much like the other aspects of this proposal, this is about embracing and extending something WordPress already does. Starting in WordPress 5.9, theme.json colors are automatically given color classes like this:

.has-primary-background-color {
    background-color: var(--wp--preset--color--primary) !important;
}

Taken further, WordPress should create a set of prefixed classes that implement every standardized design token defined in the previous section. For example, if gap 1-5 were defined in theme.json, WordPress Core, themes, and plugins could all take advantage of a custom property and standard class. WordPress could even provide fallback values for these classes to support themes that haven’t defined them yet:

:root {
    --wp-gap-3: 2rem;
}
.wp-gap-3 {
    gap: var(--wp-gap-3, 2rem);
}

Going one step further, there should be additional prefixed class names to meet the layout needs of all Core Blocks. This would cover most properties of float, grid, and flexbox. To avoid conflicts, confusion, and maintain backwards compatibility, each class should only have a single property that is reflected by the class name. This is the common approach taken by popular CSS frameworks like Tailwind. Classes would include things like this:

.wp-justify-center {
    justify-self: center;
}
.wp-align-center {
    align-self: center;
}
.wp-text-align-center {
    text-align: center;
}

Those classes could immediately be used by the Cover Block, Column/s block, Media & Text Block, Buttons block, Social Icons block, Navigation block, and probably a few more! Once a relatively small number of consistent layout classes are created, all blocks would be refactored to use these classes and would share a very small number of common styles.

And better yet, these styles—contained in a new stylesheet (wp.css?)—could be enqueued on all sites and/or called as a dependency in wp_enqueue_style so that themes and plugins wouldn’t have to ship redundant CSS.

Problems solved and positive outcomes

This proposal would address a number of long-standing issues in core and theme development:

  • Common layout needs for core blocks are addressed using a small set of shared styles
  • Plugins and core gain easy access to theme styles
  • New themes are automatically configured by custom settings from a past theme (e.g. “use the primary color” or “the biggest margin possible”)

If implemented in full, all of the following would improve or become possible for the first time:

  • CSS for core blocks would be more standardized
  • Block patterns would inherit site styles better
  • Plugins would inherit site styles better
  • Switching themes would be improved by retaining more previous content design decisions
  • Custom theme code would be more reusable
  • Less combined CSS on sites when core, themes, and plugin can all use a standard set of styles and classes

Opening new opportunities for everyone when we come together

I considered publishing this blog post as four separate ones but decided against it. Each suggestion is made stronger by combining it with the others. The sum is more than the whole, and the same can be said for the future of WordPress if it adopts a system like this one.

With a streamlined and transparent approach to design, core development will have a self-documenting, easy-to-understand set of tools for implementing future designs. When switching themes doesn’t mean losing all your content design decisions or having to remove ones that no longer make sense, users gain more freedom with their content and trust WordPress even more. And when plugins can implement site-specific design tokens in their own output, they will work and look better for site owners and site visitors alike. Every site will be more than the sum of its parts.

Get Involved

If you think this idea is worth pursuing, please give it a ❤/👍🏻 and leave some constructive feedback on this corresponding Github issue for the proposal.

If you have a clarifying question or suggestion, leave a comment!

The purpose of this proposal is to meet the needs of as many WordPress developers as possible, regardless of their roles and responsibilities. All feedback is valuable!


Appendix 1: Note on user-selected absolute values

This proposal intentionally avoids prescribing any approach for user-specified absolute values such as a 24px font size of 38vh minimum height. There are lots of smart people working on the best way to store and output those values. Inline styles or style blocks with random classnames make perfect sense for styling a single instance of a block on a page. All of the things I advocate for in this post could happily live side-by-side with a variety of solutions for this one issue.

Appendix 2: A few rationales and additional thoughts

  • Surprisingly, there is almost no discussion of design tokens in the Gutenberg repository despite how relevant it is to theme.json. The WordPress project would benefit greatly from learning from and implementing best practices around the use of design tokens.
  • For color classes and fonts, there are definitely fewer standardized tokens than the total number of defined colors in most themes I build. I think this makes sense for a few reasons:
    1. The purpose of standardization is interoperability. I think it’s much more likely that the primary and secondary colors will makes sense when inherited from prior themes than say quaternary or… quintenary? (I’m not going to look that up.)
    2. Once beyond the 4-5 standardized colors, I suspect that a named “red”, “orange”, or “yellow” color might even be more portable than a “semantic” color and less likely to result in unintended consequences.
    3. If there is a desire to extend the semantic color palette, a direction to consider would be for tokens such as success, warning, and error.
  • The maxSize design token would be intended for the width at which a site stops being full width. Not all sites do this, but many do, often around 1600-2000 pixels. This would be valuable for some media queries as well as the sizes attribute in responsive image markup.
  • Whether or not core should provide a default fallback value for every design token is an open question. I see justifications for either approach, though I think it probably makes sense to do so.
  • The potential of just a few named media queries (e.g. “two columns”) is really exciting to me. The three I included are the obvious ones I could think of, but there might be a couple more. Sadly, custom properties can’t be used in media queries, so using breakpoint design tokens will be more complicated than most other situations. However, let’s get up for this challenge and find some awesome solutions!
  • This proposal would be very backwards compatible because themes wouldn’t break by not opting in to naming conventions. However, it could be adopted quickly. Classes with undefined custom property values would have no effect, and CSS rules using undefined custom properties could provide fallbacks.

Appendix 3. Clarifications & Misconceptions (Added March 4, 2022)

The response to this proposal has been awesome! Thanks to everyone who has shared it, comments, or responded to the Github issue. Keep it coming!

After putting out the proposal, I want to clarify a few common misconceptions:

  1. The proposed standardized CSS is intended to be small. It is “incomplete” by design. It should not be a complete CSS “framework” like Bootstrap or Tailwind. That’s why I think of the standardized CSS classes generated by design tokens as a “toolkit”. It should be useful to themers, but only one tool in their belt. This is intended to only cover areas where themes can most easily be interoperable. The difference between nothing and a little bit of interoperability is huge for the WordPress ecosystem. If anything, the first priority should be getting something out the door to prove the value of the concept.
  2. The scales are relative! My initial example caused a bit of confusion which I’ve clarified. Unlike other some CSS utility frameworks, values for gap-1 and gap-2 aren’t literally 1 and 2, but the first and second values on a scale from smallest to largest. The point is that it’s up to themes to set the specific values but the relationship of those values (1 is smaller than 2 which is smaller than 3) would always be the same from theme-to-theme.
  3. These general concepts are more important than the specifics right now! Maybe there will end up being unique gap, margin, and padding values, but maybe only a generic space token is needed to create classes for all of those things. That’s worth community debate. The thing that I think is critical is finding a way to create a set of named values and standardized scales that will make content more portable from theme to theme.
  4. This isn’t intended to change other existing editor features, particularly the ability to set specific values for settings (e.g. 23px) or prevent themes from opting out of settings like padding or font-weight support.

6 thoughts on “Standardized Design Tokens and CSS for a consistent, customizable, and interoperable WordPress future”

  1. This is a great proposal. It’s similar to a complete design system and we dream of. If WP can set a standards for classes, tokens and utilities (while making them consistent, unchanged), then it helps a lot in writing themes and save a lot of custom CSS.

    We might see some HTML in combination with classes like TailwindCSS, but that’s good.

    1. So glad you like this proposal, Anh! Something that is worth clarifying is that I hope this system is very lightweight and easy to implement across a wide variety of systems. So Tailwind fans could totally take advantage of this system, but so could Bootstrap devs, totally custom sites, and even developers of core tools. This system would be the way of sharing design settings between every developer’s system of choice!

  2. This is so awesome. Thank you for taking the time to write all of this up and explain the reason behind the proposal. I think this will be a great thing for WordPress.

  3. I very much support the idea of CSS being fully integrated in the WP FSE core. First, there’s no reason to not do this 2/ CSS is designed to speed up websites and 3/ CSS has many features built into it that have been copiously standardized and made effective and efficient.

    To NOT incorporate CSS fully into the native FSE experience would be a major step back for web design. For WP FSE to fulfill its mission of expanding WP use to more sites, this should be done – at the earliest possible moment. People not very familiar with the power of CSS will soon learn to love it.

  4. So much this. You’ve not just articulated perfectly the biggest pain point many devs have had with GB, but the proposal is thought out, nondisruptive, and even if only partially adopted would keep each new GB release from being a huge source of developer anxiety.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.