How to Use SCSS in Custom Gutenberg Blocks
Custom blocks need styles that look the same in the editor and on the live site. SCSS makes those styles far easier to write: variables for your colors and spacing, nesting that mirrors the block’s markup, and mixins for patterns you repeat. Here’s how to set it up well.
Where block styles load
A block can have up to three kinds of CSS:
| Style | Loads in | Use it for |
|---|---|---|
| style | Editor and front end | The block’s real design |
| editorStyle | Editor only | Editing helpers (outlines, disabling animations) |
| viewScript (JS) | Front end only | Interactivity, not CSS |
Put almost everything in style, so the editor preview matches the site. Use editor-only styles sparingly.
The standard setup
With @wordpress/scripts, you import .scss files in your block’s JavaScript and webpack compiles them to style-index.css and index.css, referenced from block.json:
{
"style": "file:./style-index.css",
"editorStyle": "file:./index.css"
}
It works, but every style change goes through the build.
Writing good block SCSS
Scope everything to the block’s class, and use nesting for the parts:
.testimonial {
padding: $space-lg;
border-radius: $radius;
background: $surface;
blockquote {
font-size: 1.25rem;
margin: 0 0 $space-sm;
}
figcaption {
color: $muted;
&::before { content: "— "; }
}
@include up(md) {
padding: $space-xl;
}
}
Variables like $space-lg and mixins like up(md) shouldn’t be redefined in every block: they belong in shared partials.
SCSS in FanCoolo WP (no build step)
FanCoolo WP compiles SCSS inside WordPress:
- Each block has a Style tab (compiled and loaded in the editor and on the front end) and an Editor Style tab (editor only).
- SCSS Partials hold shared variables, mixins and utilities. Mark a partial global and it’s included in every block automatically, in the order you set with Global Order (lower loads first). Non-global partials can be picked per block in the block’s settings.
- Change the SCSS, save, and see it instantly thanks to hot reload.
A typical partial setup:
// Partial "Variables" (global, order 1)
$space-sm: .75rem;
$space-lg: 2rem;
$space-xl: 3rem;
$radius: 20px;
$surface: #f7f7fb;
$muted: #6b7280;
// Partial "Mixins" (global, order 2)
@mixin up($bp) {
@if $bp == md { @media (min-width: 768px) { @content; } }
@if $bp == lg { @media (min-width: 1024px) { @content; } }
}
Tips
- One source of truth for tokens. If your theme uses
theme.jsonor Tailwind, reference their CSS variables (var(--wp--preset--color--primary)) from SCSS instead of duplicating hex values. - Keep specificity low. Scope with one block class; avoid
!important. - Test in the editor as well as on the front end, especially spacing inside the editor iframe.
