Building a website these days is all about finding the right balance between a coherent and consistent design across the website and customizations capabilities that allows specific content to shine.
Far is the era where everything was customized manually (remember Dreamweaver and Frontpage?). CSS came to be, and different iterations on top of it, guidelines and frameworks exist today to ensure this consistency. Some developers still use Bootstrap, others use Tailwind, many build their own design systems. Design system, that’s a big word and a big trend these days, a promise of a coherent set of guidelines and components that can be used to ensure developers, designers and content creators are aligned and share the same expectations.
How does this translate in a CMS? How does this translate in WordPress, which runs more than 40% of the world’s websites? The answer has always been themes. While themes mean different things to different folks and have been used in different ways by different people, in their essence, they are what provides the consistency in the design of the website. They also define what content creators can or cannot customize since the degree of freedom granted to content creators might differ from one website to another depending on the context.
While WordPress continues to push its block editor and starts introducing new systems like Full Site Editing, themes live on and will remain the main entry point to define the design system and the shared guidelines for content creators.
How does this translate in a block world?
Initially, the block editor just embraced the classic WordPress APIs and approach. This meant that in order for a theme to define shared guidelines and settings, it has to rely on a set of available theme support flags. And for the design language and styles, the usage of CSS to override the default CSS styles provided in blocks is needed.
Quickly the limitations of this approach appeared:
- The block editor has a lot more customization capabilities compared to the classic editor by default, theme support flags do not scale properly and do not provide the flexibility required to control these capabilities properly (per block, per context,…)
- Blocks come with built-in CSS, and overriding the CSS to match the theme’s flavor is no easy task given the number of variations the blocks can have.
This is where Global Styles and Global Settings come in (we also talk about theme.json config to refer to these two APIs). What are these new concepts and how do they affect block and theme authors?
Theme authors
So in order to allow theme authors to provide these shared settings, WordPress and the Gutenberg project introduce the theme.json file. It’s a file that lives at the root of the theme folder and defines two important keys: settings and styles.
Settings
The settings are a list of global or contextual configuration values that define how the editor and blocks behave: which controls are disabled by default and hidden from the UI, which ones are visible. It also defines the color palette, the default typography presets (font sizes, font families…) available for editors to pick from.
// theme.json
{
"settings": {
"typography": {
"dropCap": false
}
}
}
In the example above, the theme is forbidding the use of dropCap in the UI for all blocks making use of that setting.
Settings can also be more granular and contextual to specific blocks to supports use-cases like disabling colors everywhere but enable them only for a specific block. For such use-cases, we just use the block name to define specific settings.
// theme.json
{
"settings": {
"dropCap": false,
"blocks": {
"core/paragraph": {
"typography": {
"dropCap": true
}
}
}
}
}
Styles
The styles section on the other hand is about defining the design language of the theme. It allows theme authors to define the default color, font size, line height, font family, link colors, heading sizes… At render time, it is translated into a CSS style sheet that is injected into the frontend and the editor.
// theme.json
{
"styles": {
"color": {
"text": "black",
"background": "white"
}
}
}
In the example above, I’m defining that the body (root element) of the page has a black text color and a white background.
The block editor also supports defining styles for a limited number of shared elements that can be used across blocks: links, headings.
// theme.json
{
"styles": {
"elements": {
"link": {
"color: {
"text": "blue"
}
}
}
}
}
In this example, I’m defining the color of all link (a) elements across blocks.
In the same way, I can override these styles for a specific block. In the following example, I set the default background for buttons as blue with a white text color.
// theme.json
{
"styles": {
"blocks": {
"core/button": {
"color": {
"text": "white",
"background": "blue"
}
}
}
}
}
Refer to the Global Styles documentation for a full reference of the available styles.
It’s also important to note that by using Global Styles and theme.json, editor styles generated from the theme config will be automatically loaded into the editor. Also, the presence of theme.json
file in your theme directory is an indicator for the block editor to embrace a simpler markup for some blocks like the group block.
Block authors
The shared settings and styles above work across Core blocks but third-party block authors can also support these in their blocks.
Settings
In order for a block to embrace Global Settings in its editor UI, a dedicated React hook called useSetting
can be used:
// Somewhere in your block's edit function.
// Retrieve the value of the dropCap setting
const isEnabled = useSetting( 'typography.dropCap' );
if ( ! isEnabled ) { return null };
Return <ToggleControl ... />
In this example, we’re retrieving the value of the typography.dropCap
setting and if the dropCap is enabled, we show the corresponding UI to allow content creators to use a drop cap.
That’s it: all settings can be accessed in the exact same way. For a complete list of settings available to the block authors, take a look at this reference.
Styles
Global Styles on the other hand should work mostly by default in all blocks thanks to the CSS cascade. Global Styles work by generating and injecting CSS based on theme configuration in theme.json file or saved user configuration (for FSE themes only).
So a config like:
{ "my-namespace/my-block": { color: { "text": "red" } } }
results in the following CSS:
.wp-block-my-namespace-my-block { color: red; }
That said, some blocks opt out of the generated class name which means the global styles style won’t work in this case. For these kind of blocks, a selector
must be provided in the block.json
config.
// block.json
{
"supports": {
"__experimentalSelector": ".my-custom-classname"
}
}
For this kind of blocks, the selector will be used instead of the generated class names to generate the styles.
Note: It’s important to note that a block can actually be styled using global styles even if it doesn’t provide UI for the user to edit these styles. In most situations though, support for these customizations in the UI can be added quickly to any block, static or dynamic, thanks to the Block Supports API. Also, when using Block Supports, blocks automatically adhere to the Global Settings discussed above as well.
When can I start using these?
The APIs mentioned are available when the Gutenberg plugin is active are targeted to land in Core as stable in the upcoming WordPress 5.8 release slated for July 20. If you’re a theme or block author, it’s time to start familiarizing yourself with these APIs.