Creating a custom block with styling
You can extend the built-in styling capabilities of Arc blocks to custom blocks within your feature pack. By adding just a few files to your block, the StyleBuilder script will read the styles and automatically incorporate them into the site’s stylesheet.
Deciding on creating a custom block
To guide your decision on creating and using a forked / custom block instead of an out-of-the-box block, see:
- Considerations for forking a block
- Deciding when to use an out-of-the-box block versus a custom block
Creating a custom block
You can create a custom block for any of the available types in PageBuilder Engine: output types, layouts, chains, blocks and content sources. Let’s create a custom block example by generating a new file for displaying social media links in the footer of our site:
import React, { Component } from 'react'import { Link } from "@wpmedia/arc-themes-components";
const SocialLinks = (props) => { return ( <ul> <li><Link href={}>Facebook</Link></li> <li><Link href={}>Twitter</Link></li> <li><Link href={}>Instagram</Link></li> </ul> )}
SocialLinks.label = 'Social Links'
export default SocialLinks
At this point, our block won’t function properly because we haven’t filled in the href
values for our links. If we knew the URLs we wanted to link to beforehand, we could hardcode them into our component, but we might have multiple sites with different URLs, so hardcoding won’t make sense. In this scenario, we want to use Site Properties to get the social URLs for a specific site in our environment. Let’s imagine we have 3 settings in our blocks.json
file named facebookPage
, twitterUrl
and instagramUrl
that we want to use:
import React, { Component } from 'react'import { useFusionContext } from 'fusion:context'import getProperties from 'fusion:properties';import { Link } from "@wpmedia/arc-themes-components";
const SocialLinks = (props) => { const { arcSite } = useFusionContext() const { facebookPage, twitterUrl, instagramUrl } = getProperties(arcSite)
return ( <ul> <li><Link href={facebookPage}>Facebook</Link></li> <li><Link href={twitterUrl}>Twitter</Link></li> <li><Link href={instagramUrl}>Instagram</Link></li> </ul> )}
SocialLinks.label = 'Social Links'
export default SocialLinks
Here, we’ve added two imports to help us get the site-specific URLs we want. The line import { useFusionContext } from 'fusion:context'
imports the useFusionContext function, which will give us information about what site is currently being requested later on. Then, import getProperties from 'fusion:properties';
imports the getProperties function, which will look up the specific URLs we’re looking for based on the site name. Now within the component function, we can invoke const { arcSite } = useFusionContext()
to get the current arcSite that is being requested. We can then use that arcSitevalue
to look up the URLs we need, like: const { facebookPage, twitterUrl, instagramUrl } = getProperties(arcSite)
. Finally, once we have the URLs in hand, we can plug them into their respective spots in our component.
Now our block should use the appropriate URLs defined in the file blocks.json
to generate links to our social media accounts.
Folder and file structure for styling
To enable Blocks Styling for your custom block, you’ll need two files: an _index.scss
file to define tokens for your block, and a JSON file to store the style definitions. The JSON file should be placed in a themes folder within your block and must be named to match the theme specified in the blocks.json
file — typically, this theme is set to news
.
This styling approach is not limited to custom blocks. You can use this structure to create styling tokens for custom chains, layouts, output-types, or any other custom folder nested under components
.
Your block’s folder structure goes from something like this:
Directorycomponents
Directoryfeatures
Directorymy-custom-block
- default.jsx
to this:
Directorycomponents
Directoryfeatures
Directorymy-custom-block
- _index.scss
- default.jsx
Directorythemes
- news.json
Directorychains (example/optional)
Directorymy-custom-chain
- _index.scss
- default.jsx
Directorythemes
- news.json
Directorylayouts (example/optional)
- …etc
Directoryoutput-types (example/optional)
- …etc
Directorycustom-folder (example/optional)
- …etc
Normally, including styles in your block requires an import
statement pointing to the style file’s location. However, with the Blocks Styling approach, this step is not needed.
Creating tokens
With the necessary files and folders created, you can begin to create tokens that Blocks Styling uses to apply the desired styles. At the top of the new _index.scss
, you must include the statement @use "@wpmedia/arc-themes-components/scss";
to import our SCSS library’s mix-ins to process the tokens that it adds in a future step. To add a new token, create a SCSS rule and add @include scss.block-components("my-block-token");
and @include scss.block-properties("my-block-token");
. The top level rule should be targeting a class on the outermost wrapper of your block.
Your _index.scss
should now look something like this:
@use "@wpmedia/arc-themes-components/scss";.my-block-wrapper { @include scss.block-components("my-block"); @include scss.block-properties("my-block");}
Tokens can be added to any valid SCSS rule, but grouping them under a single top-level rule helps avoid styling scope issues. Be careful not to redefine existing tokens. You can also target pseudo-elements by creating tokens specifically for them. A more complete _index.scss
file might look like this:
@use "@wpmedia/arc-themes-components/scss";.my-block-wrapper { @include scss.block-components("my-block"); @include scss.block-properties("my-block");
&-left-container { @include scss.block-components("my-block-left"); @include scss.block-properties("my-block-left");
&:before { @include scss.block-components("my-block-left-before"); @include scss.block-properties("my-block-left-before"); } }}
With that, you now have some tokens defined, and you can move on to adding styles.
Adding styles to tokens
Now we can start adding styles to the themes/[my-theme].json
. This JSON file includes an entry on the root node for each token you created. Using the example _index.scss
from the previous section, the skeleton of the JSON file would look like this:
{ "my-block": { "styles": { "default": {}, "desktop": {} } }, "my-block-left": { "styles": { "default": {}, "desktop": {} } }, "my-block-left-before": { "styles": { "default": {}, "desktop": {} } }}
In this example, the default
and desktop
entries refer to breakpoints. These two breakpoints are provided out of the box in Themes (see Breakpoints for how to define custom breakpoints). For each breakpoint, you define styles by listing CSS properties within the corresponding object and assigning appropriate values. For example:
{ "my-block": { "styles": { "default": { "display": "block" }, "desktop": { "display": "flex" } } }, ...}
The values could also be the global and alias tokens made available in Blocks Styling:
{ "my-block": { "styles": { "default": { "color": "$global.neutral-4", "display": "block", "font-family": "$alias.font-family-secondary" }, "desktop": { "display": "flex" } } }, ...}
If you are using components from @wpmedia/arc-themes-components
in your custom block, you can style those directly without the need for extra tokens. To style those components, use the component
key in your JSON file. For example, in your block’s output, use the <Paragraph>
component to output some text. You can style that component like this:
{ "my-block": { "styles": { "default": { "color": "$global.neutral-4", "display": "block", "font-family": "$alias.font-family-secondary", "components": { "paragraph": { "margin-block-end": "$global.spacing-4" } } }, "desktop": { "display": "flex" } } }, ...}
This code sample styles all uses of the <Paragraph>
component used within your blocks wrapper. Placing these styles in other tokens affects only the uses of those components within that tokens scope. If you want a larger margin on just the <Paragraph>
components in the .my-block-wrapper-left-container
we defined a token for earlier, we could do so like this:
{ "my-block": { "styles": { "default": { "color": "$global.neutral-4", "display": "block", "font-family": "$alias.font-family-secondary", "components": { "paragraph": { "margin-block-end": "$global.spacing-4" } } }, "desktop": { "display": "flex" } } }, "my-block-left": { "styles": { "default": { "components": { "paragraph": { "margin-block-end": "$global.spacing-6" } } }, "desktop": {} } },}
The <Paragraph>
component is just an example. You can use this method with any of the component tokens listed in the Styling section if you use those components in your block’s code.
Adding site-specific styles
You may want to utilize different styles per site. To acheive this, add a site specific style for your block/component combination. Here’s a code example of a basic custom block:
import React from 'react';import { Link } from "@wpmedia/arc-themes-components";
const BLOCK_CLASS_NAME = "b-custom-link-block";
function CustomBlockWithLink() { return ( <div className={ BLOCK_CLASS_NAME }> <Link href={}>Click for other reward</Link> </div> )}
CustomBlockWithLink.icon = "user-question";CustomBlockWithLink.label = "My Custom Block With A Link";
export default CustomBlockWithLink;
Set up the tokens for this block
@use "@wpmedia/arc-themes-components/scss";.b-custom-link-block { @include scss.block-components("my-custom-block-token"); @include scss.block-properties("my-custom-block-token");}
Set a default style:
{ "my-custom-block-token": { "styles": { "default": { "components": { "link": { "text-decoration": "none" } } } } }}
In order to set a site specific style, add the following file (or append the existing file):
{ "my-custom-block-token": { "styles": { "default": { "components": { "link": { "text-decoration": "underline" } } } } }}
For more details on Blocks Styling, see Introduction to Themes design system.
Variants and custom tokens
In addition to creating styles for your custom blocks, you can also create variations of non-custom blocks by creating tokens for certain SCSS rules. To start, add a customTokens
folder to your feature pack, along with an _index.scss
and a themes/[my-theme].json
file. Your feature pack should look something like this:
- blocks.json
Directorycomponents
- features
DirectorycustomTokens
- _index.scss
Directorythemes
- news.json
- content
- …etc
With that set up, you can create new tokens for out-of-the-box blocks. By adding a rule for a block’s class in this new SCSS file, you can then style it specifically based on its location in a layout, if it’s in a specific chain, or if it’s the last instance of a block in the same container.
For example, if you wanted to change the font size of the Card List Block’s title but only on desktop and if it’s in the rightrail
section of the default Right Rail - Arc Layout, you could do so. Inspecting the Card list block, you can see the title has the class b-card-list__title
. Then checking the right rail section of the Right Rail layout, you can see it has the class b-right-rail__main-right-rail
. Knowing this, you can now create a token in the customTokens/_index.scss
:
.b-right-rail { &__main-right-rail { .b-card-list { &__title { @include scss.block-components("card-list-title-right-rail"); @include scss.block-properties("card-list-title-right-rail"); } } }}
With the token created, you can style it in the customTokens/themes/[my-theme].json
:
{ "card-list-title-right-rail": { "styles": { "default": {}, "desktop": { "font-size": "$global.font-size-5" } } }}
You’ve now created a variant of an out-of-the-box block, without the need to eject and fork the block. There are countless ways to use this functionality — this is just one example.
As noted above, ensure you run your bundle locally first to build the styles and re-upload your bundle with the applied changes for your deployment.
Lastly, if you do have custom code that adds classes conditionally to a page, template, or is a custom-built chain, then you can create variants of out-of-the-box blocks based on those classes here as well. The only difference from the previous example is that you would use those custom classes in targeting a block.