Theme.json configuration with modern Sass (SCSS) features (@use, @forward)
Chisel theme combines WordPress’s
theme.jsondesign tokens with a modular SCSS architecture. Global styles (color palette, typography, spacing, etc.) are declared intheme.jsonand emitted as CSS Custom Properties, while SCSS composes styles via@use/@forwardfor clear, dependency‑safe modules.
Overview
- theme.json: Defines colors, typography, spacing scale, layout, and custom tokens exposed as CSS variables.
- Sass modules: Design system split into
settings(Sass variables) andtools(functions/mixins) using@use/@forward. - Goal: Create styles with stable design tokens while staying aligned with WordPress Global Styles.
theme.json highlights
Colors
Custom palette (Primary, Secondary, Greys, etc.) available in CSS as --wp--preset--color--{slug} and in SCSS via get-color($slug)
Example:
{
"settings": {
"color": {
"palette": [
{ "slug": "primary", "color": "#dd2424", "name": "Primary" },
{ "slug": "background", "color": "#ffffff", "name": "Background" }
]
}
}
}JSONSCSS Usage:
@use '~design' as *;
.my-component {
color: get-color('primary');
background-color: get-color('background');
}SCSSTypography
Fluid font sizes and a curated scale (tiny → huge).
- Font Sizes: Available via
get-font-size($slug)(e.g.,normal,large,huge). - Font Families: Defined in theme.json and loaded via local assets. Access via
get-font-family('body')orget-font-family('headings').
Example:
{
"settings": {
"color": {
"typography": {
"fontSizes": [
{ "slug": "tiny", "size": "0.75rem", "name": "tiny" },
{ "slug": "normal", "size": "1rem", "name": "Normal" },
{ "slug": "large", "size": "1.25rem", "name": "Large", "fluid": { "min": "1.125rem", "max": "1.25rem" } }
],
"fontFamilies": [
{
"fontFamily": "Roboto,sans-serif",
"slug": "body",
"name": "Roboto",
"fontFace": [
{
"fontFamily": "Roboto",
"fontWeight": "300",
"fontStyle": "normal",
"fontStretch": "normal",
"fontDisplay": "swap",
"src": ["file:./assets/fonts/roboto-300.woff2"]
},
{
"fontFamily": "Roboto",
"fontWeight": "700",
"fontStyle": "normal",
"fontStretch": "normal",
"fontDisplay": "swap",
"src": ["file:./assets/fonts/roboto-700.woff2"]
}
]
}
]
}
}
}
}JSONSCSS Usage:
@use '~design' as *;
.my-component {
font-family: get-font-family('body');
font-size: get-font-size('normal');
}SCSSCustom Tokens
Chisel defines a robust set of custom tokens in settings.custom for consistent design system usage:
- Spacing (Margin/Padding/Gap):
tinytohugescale. - Border Radius:
tinytofull. - Border Width:
tinytolarge. - Box Shadow: Levels 1-4.
- Transitions:
slow,normal,fast. - Line Height/Letter Spacing.
How theme.json and Sass connect
Theme tokens are CSS variables. SCSS functions in src/design/tools/_theme.scss provide ergonomic wrappers:
// src/design/tools/_theme.scss
@function get-padding($name) {
@return var(--wp--custom--padding--#{$name});
}
@function get-transition($name: 'normal') {
@return var(--wp--custom--transition--#{$name});
}SCSSThis ensures that if you change a value in theme.json, all your SCSS automatically reflects the change without recompiling, because it relies on the CSS variable.
Best practice: Create components using functions/tokens instead of literals:
@use '~design' as *;
.card {
padding: get-padding('medium');
color: get-color('foreground');
@include bp('medium') {
// bp() is defined in design/tools/_breakpoints.scss
padding: get-padding('large');
}
}SCSSUsing @use and @forward
Chisel uses the modern Sass module system to prevent global variable namespace pollution.
Global Design Import
In your component files, import the design system:
@use '~design' as *;
.c-card {
padding: get-padding('medium'); // Function from 'tools'
background: get-color('white');
@include bp('medium') { // Mixin from 'tools/breakpoints'
padding: get-padding('large');
}
}SCSSSpecific Imports
If you only need settings (like Sass variables for breakpoints or grid config):
@use '../design/settings' as settings;
.c-grid {
gap: map.get(settings.$gaps, 'normal');
}SCSSExtending the Design System
- Add a new tool/mixin: Create
src/design/tools/_my-mixin.scss. - Forward it: Edit
src/design/tools/_index.scssto add@forward 'my-mixin';. - Use it:
@use '~design' as *; @include my-mixin();.
Why this architecture?
- Single Source of Truth:
theme.jsoncontrols the values. - Performance: CSS variables allow browser-native theming and updates without CSS bloat.
- Maintainability: Sass modules (
@use) make dependencies explicit—no more guessing where a variable comes from. - Standards: Fully aligned with WordPress Full Site Editing (FSE) and Gutenberg block styles.
Using @use and @forward (Sass modules) — short guide
@use
@use imports a Sass module once and namespaces its members (variables, mixins, functions).
Basic:
@use '../design/tools'; // access as tools.$var, tools.fn(), tools.mixin()
@use '../design/tools' as *; // flatten into current scope (be careful with naming)
@use '../design/tools' as t; // custom namespaceSCSSWith configuration (override module variables at load time):
@use '../design/settings' with (
$root-font-size: 18px
);SCSS@forward
@forward re-exports members from another module to build a public API.
In the theme, src/design/_index.scss.This means consumers can just:
@forward 'tools';SCSS@use '../design' as *; // gets everything forwarded by tools/_index.scssSCSSYou can curate exports in a tools/_index.scss:
// src/design/tools/_index.scss
@forward 'breakpoints';
@forward 'px-to-rem';
@forward 'theme';
// etc.SCSSWhy modules (vs @import):
- Single evaluation, no duplication.
- Namespacing avoids collisions.
- Clear, composable public API via
@forward.