Sage and Editor Styles


I’m just getting to grips with Sage and seem to be going round in circles on a robust way of wrapping my CSS in the .editor-styles-wrapper selector for scoping my CSS in the block editor. In other projects I have used the PostCSS plugin postcss-prefix-selector for this and run 2 build steps, one for app.css and one for editor.css. I then end up with a second CSS file (editor.css) which is an exact copy of app.css but every rule is wrapped in .editor-styles-wrapper. I’m struggling to achieve this in Bud. Is this even the right approach or is there a better way? There are a number of posts on this on this forum which all suggest different solutions…


Hi there!

Can you show us the specific code that you’ve tried? What wasn’t working?

It’s the right approach if that’s what you’re wanting to do. Is there a better way? Maybe. It really depends on what you think works best for you, which is part of the reason why Sage has left it up to you to decide how you’d like to style things in the editor.

Different folks have different solutions. What approach works best for you and your colleagues?

Thanks for coming back Ben, and sorry for my lack of detail. So this is my bud config. It works without the call to app.postcss.setPluginOptions(). But when I include the setPluginOptions call I get 11 errors (1 per CSS dependency) saying Error: Loading PostCSS "/" plugin failed: Cannot find module '/'. I’m confident the options themselves are valid as I’ve copied and pasted them from my laravel mix config in another project. Appreciate your help!

export default async (app) => {

    ['tailwindcss']: await app.module.resolve('tailwindcss'),
    ['nesting']: await app.module.resolve('tailwindcss/nesting/index.js'),
    ['postcss-prefix-selector']: await app.module.resolve('postcss-prefix-selector'),
    ['autoprefixer']: await app.module.resolve('autoprefixer'),

  app.postcss.setPluginOptions('postcss-prefix-selector', {
    prefix: '.editor-styles-wrapper',
      transform(prefix, selector, prefixedSelector, filePath, rule) {
        if (selector.match(/^(html|body)/)) {
          return selector.replace(/^([^\s]*)/, `$1 ${prefix}`);
        if (filePath.match(/node_modules/)) {
          return selector; // Do not prefix styles imported from node_modules
        const annotation = rule.prev();
        if (annotation?.type === 'comment' && annotation.text.trim() === 'no-prefix') {
          return selector; // Do not prefix style rules that are preceded by: /* no-prefix */

        return prefixedSelector;

     * Application entrypoints
      app: ["@scripts/app", "@styles/app"],
      editor: ["@scripts/editor", "@styles/editor"],

     * Directory contents to be included in the compilation

     * Matched files trigger a page reload when modified
    .watch(["resources/views/**/*", "app/**/*"])

     * Proxy origin (`WP_HOME`)

     * Development origin

     * URI of the `public` directory


My two cents here (of course, everyone should use what fits best): I would register the frontend styles as editor styles and let the Gutenberg Editor post-process those styles and wrap the selectors with .editor-styles-wrapper, see this example in the Sage 10 Full Site Editing (FSE) sample theme:


Thanks @strarsis. I had no idea Gutenberg offered this functionality! This seems a much more elegant solution. Sadly it doesn’t seem to be working for me right now, my styles are getting queued and are being loaded but are not being inlined of prefixed. Documentation seems a little sparse on this feature on the WP side. Anyway, it seems that this isn’t a Sage issue so I’ll do some more digging.

Whilst we’re on topic though, my current configuration (which is the default Sage 10 configuration with bud), is producing assets with a random string in the filename (ie. app.e3d516.css). How would I enqueue these without hard-coding this string, which changes each build? I suspect it has something to do with bundle() but can’t find anything on this in the docs.


This what asset('...') is used for in the example linked above. It can be used to get the correct path.

1 Like