dark_mode

Atlas Layouts

Custom Layout blocks: Layouts with controls.


The simplest custom block is a "pure layout" block. This means we're defining a specific, nested layout of other blocks. With a bare minimum of code-writing, and no knowledge about how Gutenberg works, you can already create this type of block.

Everyone uses layouts in web development -- patterns that we want to repeat, even if just a few times. In React, we typically create a component for that, maybe calling it a "molecule" or "organism."

That's what we're doing in Atlas too, except it will be a block that appears in Gutenberg, that is WYSIWYG, and that gives the front-end developer fine-tuned control over what the Gutenberg author is allowed to do.

Defining the layout

Let's define a layout called "Feature." This will be a column that includes an icon, a title, and a description of a feature in a product. We want to be able to create a "Feature" as a single block in Gutenberg.

Every custom block in Atlas is a directory containing a few files with specific names. You can put these directories anywhere; for simplicity, we'll assume there's a directory called blocks off the root of the project.

Start by creating the following files (notice the file extensions!):

/blocks/feature/editor.js
/blocks/feature/meta.ts
/blocks/feature/index.ts

For complex custom blocks, with their own properties, custom Gutenberg editors, custom React components, and custom SCSS, you will use all of these files. For layouts, however, we have shortcuts where we can ignore all that.

editor.js defines the Gutenberg editor. The entire file can be just the following, using an Atlas short-cut utility that works for any pure-layout block:

export { PureLayoutEditor as default } from 'gutenberg'

index.ts defines the React component. Again the entire file can be just the following, using an Atlas short-cut utility, and including something from meta.ts which we'll implement next:

import { registerPureLayoutSuperblock } from '@asmartbear/gutenberg-bridge/dist/react-util';
registerPureLayoutSuperblock(require('./meta').default);

Now for the real work! in meta.ts we define the "meta-data" for the custom block. This includes all the information needed for Gutenberg, for Storybook, for React, as well as for the layout of blocks. Here'e the complete implementation, followed by an explaination:

import { Props, SuperBlockMeta, makeLayout } from '@asmartbear/gutenberg-bridge/dist/types';
import iconDefinition from '@asmartbear/gutenberg-bridge/dist/blocks/atlas-material/icon/meta';
import boxDefinition from '@asmartbear/gutenberg-bridge/dist/blocks/atlas/box/meta';
import proseDefinition from '@asmartbear/gutenberg-bridge/dist/blocks/atlas/prose/meta';
const definition: SuperBlockMeta<Props> = {
uiType: 'tutorial/feature',
blockMeta: {
title: "Feature",
description: "An icon, title, and description of a product feature",
},
propsMeta: {
},
gutenbergMeta: {
dashicon: "layout",
category: "tutorial",
},
layout: [
makeLayout({
atlasId: "outer",
block: boxDefinition,
props: { maxWidth: "375px" },
children: [
makeLayout({
atlasId: "icon-container",
block: boxDefinition,
props: { alignH: "center", marginBottom: 1 },
children: [
makeLayout({
atlasId: "icon",
block: iconDefinition,
props: { color: "primary", sizePx: 16 * 4, backgroundVariant: "circle" },
allowChange: ["icon"],
}),
]
}),
makeLayout({
atlasId: "headline",
block: proseDefinition,
props: { backgroundColor: "backdrop", textSize: 130, placeholder: "An incredible feature", align: "center", whiteSpace: "nowrap" },
allowChange: ["content"],
}),
makeLayout({
atlasId: "explain",
block: proseDefinition,
props: { backgroundColor: "backdrop", textSize: 100, align: "center", placeholder: "A full description of the benefits of this feature." },
allowChange: ["content"],
}),
],
}),
],
};
export default definition;

Let's unpack everything:

uiType: 'tutorial/feature'
Gutenberg blocks are required to have a unique, namespaced name, in this format. Atlas uses the same convention, so there's just one way to refer to defined type of block.
blockMeta
Meta-data about the block, used to inform documentation inside the Gutenberg editor, and in Storybook. There are a few additional, optional fields you might want to check out.
propsMeta
Empty in this case, but this is where you will declare custom properties for the block. We'll get to that in a later chapter.
gutenbergMeta: { dashIcon: ... }
dashicon assigns a standard WordPress icon to the block, for display in the block-insertion UI. Here is the list of choices. Grab the name by looking near the top of that page, ignoring the "dashicons-" prefix.
gutenbergMeta: { category: ... }
Category under which to list the block in the Gutenberg block directory. You can use one of the standard WordPress categories, or invent your own. The WordPress theme generator will automatically register your custom categories.
layout
Here's where we define the actual layout of blocks.

Each block is wrapped in the makeLayout() utility. Most of the contents are self-documenting -- the block's definition, any properties (all optional), and optionally a list of children. The other fields we'll describe next.

Here Typescript is our friend, with the block-definition objects keeping us honest about what properties we can set, to what data types, or what fields can be listed under "allow changes." No silly bugs!
makeLayout({ atlasId: ... })
Each element is given an ID, unique within this layout. This serves a variety of purposes, including automatically-generated CSS classes, but perhaps the most powerful benefit is that it allows you to change the layout later, and existing blocks are automatically reconfigured, both on the React side (i.e. even if Gutenberg hasn't updated), and in Gutenberg.

This solves a traditionally intractable problem. The typical problem is: You create a set of blocks, but then you want to change the template. The blocks, however, are already created; there's no way to update them afterwards. You have to find all examples of blocks, everywhere in the web site, and manually update those settings. That's bad for properties, and worse if it involves adding more blocks! Atlas automatically solves this problem; all you have to do is set these unique IDs, so it can track existing blocks against new layouts.
makeLayout({ allowChange: [...] })
By default, the Gutenberg author is not allowed to alter any properties of any blocks. This allows the front-end designers and developers to "lock down" the layout. Of course, the Gutenberg author should have power over something! In this field, you list properties that are allowed to be changed. In this case, we're providing the ability to change the icon, and the text in the prose areas.
makeLayout({ props: { placeholder: ... } })
An special property is placeholderText. This is content that can be placed in blocks like paragraphs and headings, which creates a grayed-out placeholder in the visual editor, prior to the user supplying actual content. You can see this in action in the screenshot below.

There's one last thing to do: Configure the WordPress theme-builder, so it knows to include your new custom block. Add the path to your blocks root directory to the package.json configuration:

{
"atlas": {
"config-json": "./atlas-block-config.json",
"theme-dest": "./wp-theme",
"block-css-output-file": "css/block.css",
"block-dirs": [
"node_modules/@asmartbear/gutenberg-bridge/dist",
"blocks"
]
}
}

To see the new block in action, recreate the theme and upload it to WordPress. The new block appears in the insertion menu, including an automated preview, featuring information from the block meta-data:

[image]

Here's an example where we enclosed three "Features" in an Atlas Grid block, so that these features will arrange themselves in a row if there's enough horizontal space, or a column if there's not. Note how the Icon block is allowing the operator to change the identifier, but none of its other fields:

[image]

Back on the React site, everything looks exactly the way it looks in Gutenberg, except now it's responsive to browser widths, changing layout and also diminishing text size when things get narrow, and supporting dark-mode:

[image]

Adding SCSS to the layout

Sometimes you'll want to tweak the layout with additional CSS styles. This is a handy way to fine-tune things without having to implement completely new blocks, or to use CSS selector functionality like :hover.

The layout system automatically applies a CSS class for overall layout block, and a CSS class for each component. The parent layout receives a CSS class based on the uiType of the block, so in our example, tutorial/feature becomes the CSS class tutorial-feature. Then, each component inside the layout receives a CSS class of atlas-layout-XYZ, where XYZ is the atlasId field.

To implement your CSS classes, all you have to do is create a file called styles.scss in your block's directory. The WordPress theme builder utility automatically discovers and bundled these into the WordPress theme as well as that front-end CSS file you named using block-css-output-file in package.json. In short, you just create styles.scss, and everything just works after you rebuild the theme.

In our example, we could add a grey overbar to the Feature's title, like this:

.tutorial-feature {
.atlas-layout-headline {
border-top: 1px solid #808080;
}
}

This system works in both React and in Gutenberg, preserving WYSIWYG editing.

Now that we're able to create a pure-layout custom block, we're ready to tackle arbitrarily-complex custom blocks, with properties and fancy Gutenberg editors.

  • Getting Started with the Gutenberg / React Bridge
    Display blocks from Gutenberg, and creating a WordPress Theme for WYSIWYG editing inside Gutenberg.
  • Atlas Blocks
    The built-in Atlas blocks, in React and in Gutenberg.
  • Atlas Layouts
    Custom Layout blocks: Layouts with controls
  • Atlas Custom Blocks
    How to create new React components that automatically generate Storybook documentation and rich, composable Gutenberg blocks.
  • Atlas Slabs
    Mocking up and filling sections within a React page, using sections within Gutenberg.
  • Atlas Theming
    A complete system of color, typopgraphy, and layout, supporting dark mode, Gutenberg, and Storybook
  • Storybook Integration
    How to automate Storybook stories for everything - custom, WordPress Core, and Atlas blocks.
  • Storybook Reference
    Storybook-based interactive documentation for Atlas Core and Gutenberg Core blocks.