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:

StyleLoads inUse it for
styleEditor and front endThe block’s real design
editorStyleEditor onlyEditing helpers (outlines, disabling animations)
viewScript (JS)Front end onlyInteractivity, 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.json or 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.
SCSS for blocks, without webpack

SCSS for blocks, without webpack

FanCoolo WP compiles block SCSS inside WordPress, with shared global partials and hot reload.