Search code examples
csswordpressreact-hookswordpress-gutenberggutenberg-blocks

Add styles of class of external css file to Block props to use as attributes


Is it possible to use styles of a class in an external css file ( which is added to the block.json) as props to use these as attributes in the InspectorControls Component, if so, how?

I know that I can use inline styles as attributes for the InspectorControls Component. But dont know any way to use certain parts of classes in the external css files.

My css file added to the blocks.json:

  "editorScript": "file:./index.js",
  "editorStyle": "file:./editor.css",
  "style": "file:./style.css"

I want to use Method 2 from this wordpress docs page for my classes and then use parts of the classes as attributes.


Solution

  • Yes, by importing the class names from a CSS module as the options for a UI control (eg <SelectControl>) the class can be applied to the block with useBlockProps().

    In the example below, I used create block to setup a simple block that renders a paragraph which the user can choose the color "theme" of. It's best to use a CSS file containing only the classes you wish to load into the UI component, eg:

    theme.scss (or an external css file)

    .red{
        color:red;
        border-color: red;
    }
    .blue{
        color:blue;
        border-color: blue;
    }
    

    Create a new SCSS file with CSS modules in block/src to import the external styles:

    classes.module.scss

    @import './theme.scss';
    

    Import the same external CSS in the blocks main style so it will be compiled into style.css, eg:

    style.scss (main block styles)

    @import './theme.scss';
    .wp-block-gutenberg-default-block{
        /* all custom styles for the block */
        padding: 1em;
        border:2px solid;
    }
    

    Alternatively, you could enqueue the stylesheet separately via PHP or via the theme..

    Add a new string attribute to store the name of the class selected from the UI/SelectControl, eg:

    block.json

    {
        ...
        "attributes": {
            "customClassName": {
                "type": "string",
                "default": ""
            }
        },
        "editorScript": "file:./index.js",
        "editorStyle": "file:./index.css",
        "style": "file:./style-index.css"
    }
    

    By naming the importing the CSS module in edit(), we can have access an Object containing all the classes from theme.scss. Before displaying in the UI, the class names are formatted as options for a <SelectControl>. The selected class name is saved to the blocks attributes and applied by useBlockProps(), eg:

    edit.js

    import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
    import { PanelBody, SelectControl } from '@wordpress/components';
    
    import styleClasses from './classes.module.scss';
    
    export default function Edit({ attributes, setAttributes }) {
        const { customClassName } = attributes;
        const myClasses = [{ label: 'none', value: '' }]; // Default option for SelectControl
        
        // Add each classname in styleClasses to myClasses
        for (const key in styleClasses) {
            myClasses.push({ label: key, value: key })
        }
    
        return (
            <>
                <InspectorControls>
                    <PanelBody>
                        <SelectControl
                            label="Custom Class"
                            value={customClassName}
                            options={myClasses}
                            onChange={(value) => setAttributes({ customClassName: value })}
                        />
                    </PanelBody>
                </InspectorControls>
                <p {...useBlockProps({ className: customClassName })}>Hello World</p>
            </>
        );
    }
    

    Finally, useBlockProps.save() wraps the selected classname into the blocks markup on save.

    save.js

    import { useBlockProps } from '@wordpress/block-editor';
    
    export default function save({ attributes }) {
        const { customClassName } = attributes;
    
        return (
            <p {...useBlockProps.save({ className: customClassName })}>Hello World</p >
        );
    }
    

    End result: SelectControl to choose class name Hopefully this will give you some ideas for what's possible in your own block with CSS and attributes.