Every page on your site is a stack of blocks. A block is one piece of a page: some text, a picture, a button, a map, a pair of columns. You build a page by adding blocks in the page editor and filling in their fields. No code is needed.
This chapter takes you from an empty page to a published one. By the end you can add a page, lay blocks out side by side, put a code sample on a page, change the header and menu that every page shares, and decide who may open a page.
A page has two versions. Saving a draft changes only the draft, so visitors keep seeing the live page until you publish. History lists every saved version, newest first. Restore on an older one publishes it again and makes it your draft.
The left side has the Blocks list, where you pick blocks to add, and an Outline tab that shows the page as a tree, which helps when blocks sit inside other blocks. The middle is a preview of the page. The right side shows the fields of the block you have selected.
The bar along the top has the page's name and address, then ← Pages (back to the list), a Live or Draft badge, Settings, History, Preview, Save draft and Publish.
A block's fields are grouped. Content holds what the block says or shows. Settings holds how it looks and behaves. Spacing, width and other size fields sit in groups of their own that start closed. Show on and Show to come last.
Two things are called settings. The Settings button in the top bar opens the page's title, parent page and URL, with Delete and Unpublish. Clicking an empty part of the preview, outside every block, opens the page's own fields on the right: Layout, Page title, Meta description, Social image URL, Search engines and Access. The four in the middle are explained in Search engines.
The Blocks list is grouped by what the blocks are for. Most of what you need is under Elements:
| To do this | Use |
|---|---|
| Write text, headings and lists | Text |
| Show a picture | Image |
| Show a set of photographs that open larger | Gallery |
| Add a button or a plain link | Button, Link |
| Put blocks side by side | Columns |
| Put small items on one line, such as icons | Inline |
| Stack blocks with an even gap | Rows |
| Give part of the page its own background and width | Section |
| Add empty space or a line | Spacer, Divider |
| Add a symbol or a social media mark | Icon |
| Show places on a map | Map (Maps) |
| Questions and answers | FAQ for text answers, Accordion for panels that hold any blocks |
| A few cards, each with a title, text, picture and link | Card grid |
| Prices or opening times | Table |
| Logos of sponsors or partners | Logo strip |
| Commands and configuration | Code |
The other groups are Hero (the opening band of a page), Site (Navigation, Footer and Page content, which belong in layouts), Lists (the “List of…” block and the blocks that show one field or link of an item), and Users (sign-in, registration and password forms, and the account icon). Forms, Polls, Questionnaires, Commerce, Posts and Appointments appear only on a site that has that feature (Try it on your computer shows how to add one). Custom holds blocks your own site adds.
Some blocks hold other blocks. The place inside a block where other blocks go is called a slot. A Section has one slot and Columns has one for each column. A block inside a slot can have slots of its own.
Order when stacked can be Reversed, which puts the last column first once they pile up. That suits a picture beside text when you want the text on top on a phone.
A Section is a band across the full width of the page. Put one around each part of a page and drag that part's blocks into its slot. A Section has a Background and Text colour, Top & bottom padding and Side padding, Corners, a Width (how wide the content may grow before it is centred) and Text alignment.
Rows stacks two to six slots with an even gap and can draw a rule between them. Inline puts small blocks on one line, each at its own width: a few social icons, or a button beside a line of text. Its slot is called Items. Drop a new block between two others, or drag an item sideways to move it. Align offers Left, Centre, Right and Spread out. Setting Wrap onto more lines to No keeps the row on one line and shrinks its items instead.
You never type a padding or a colour as a number. Each field offers the sizes, colours and text styles the theme defines. These named choices are the theme's tokens. They keep every page consistent, and a change in Settings → Theme restyles the whole site.
Text, Image, Button, Link, Spacer, Divider and Inline have a Spacing field: padding around the block's own box, for each side a theme size or a pixel value. Icon, Map and Code have the same field, called Padding. Use it for a one-off gap. To space every block in a group evenly, use the gap of the Columns, Rows or Inline block that holds them, or add a Spacer.
Padding, gaps, widths and heights can differ by screen size. Such a field has a Default, which applies from the smallest screens up, and one entry for each larger size, labelled “≥ md (48rem)” and so on. Leave an entry on Unchanged to keep the value from the size below it.
Every block has a Show on field with a tick box for each screen size: Phone, Tablet, Laptop and Desktop, each with the widths it covers. A block that is not ticked for a size is hidden at that size. Each column of a Columns block has its own, under Show columns, and so does each row of a Rows block. In the editor a hidden block stays in the preview, dimmed, so you can still select it.
The Code block, in Elements, shows commands, configuration files and snippets. It colours the code for its language, can number the lines, mark some of them, and gives visitors a button that copies all of it. Use it instead of a preformatted paragraph in a Text block, which stays plain.
compose.yaml tells the reader which file the lines belong to. Leave it empty for no bar.| Field | What it does |
|---|---|
| Colours | Site default follows the colour scheme chosen in Settings → Theme. Pick one of the eight schemes to give this block its own (see Theme). |
| Line numbers | Yes draws a number beside each line. The numbers are not copied with the code. |
| Highlight lines | Gives some lines a lighter background. Write line numbers separated by commas, and a range with a hyphen: 2, 5-7 marks line 2 and lines 5 to 7. Lines are counted from the first line of the code, whether or not numbers show. Anything else in the box is ignored. |
| Wrap long lines | Yes folds a long line onto the next. No, the default, keeps each line whole and lets the code scroll sideways. |
| Copy button | Yes, the default, shows a button that copies all the code. |
| Copy button text | The button's words. The default is Copy. |
| Text after copying | What the button says for two seconds after a click. The default is Copied. |
| Padding | Space around the block. By default it has some above and below. |
The two button texts appear only while Copy button is Yes. They are fields so that you can write them in your visitors' language.
The copy button sits in the top right corner of the block, or at the end of the file name bar when there is one. It appears once the page has loaded in the visitor's browser, so nobody sees a button that does nothing. In the editor it is drawn but does not copy.
The Icon block opens a picker with a tab for each set of icons. Lucide is always there: about 1,850 symbols, picked by name. Brands comes with the cms and holds brand:facebook, brand:instagram, brand:x, brand:linkedin and brand:bluesky. Use a brand mark to link to your own page on that service, and give the icon a label that says where it goes, because the label is all a screen reader has. The marks are their owners' trademarks.
A developer can add a tab of the site's own icons. An icon is path data, not an image file, so there is nothing to upload. Define the set in the site's block package, blocks/index.ts, and list it under icons, keeping the rest of the file as it is. A style of 'fill', the default, draws a solid shape. A style of 'stroke' draws a line like the Lucide icons, and the block's Stroke width applies.
import { defineBlockPackage, defineIconSet } from '@jamiemcconnell/cms/blocks';
const ourIcons = defineIconSet({
name: 'site',
label: 'Our icons',
icons: {
chevron: { title: 'Chevron', paths: ['M6 4l8 8-8 8'], style: 'stroke' },
},
});
export default defineBlockPackage({
name: 'site',
blocks: [
// Your own blocks stay here, with any collections and styles you have.
],
icons: [ourIcons],
});The new tab is called Our icons, and the icon is picked as site:chevron.
A layout is the frame around every page: the header at the top and the footer at the bottom. You edit it once and every page changes. The layout that every page uses unless it says otherwise is called default.
To use another layout on one page, click an empty part of the page's preview and change its Layout field: Default, another named layout, or None, which gives the page no header and footer so you can build your own. Make a new layout with New layout on Content → Layouts and choose Site layout as its Type. Email layouts are covered in Emails.
A menu is an ordered list of links. The Navigation block shows one, usually in the header of a layout.
Links from has two other choices. Pages lists your pages as they are nested; to nest a page under another, set its Parent page in the Settings button, as these docs are nested under Docs. Custom links lets the block carry a list of its own. The Who sees it column on a menu link limits that link to some visitors, in the same way as Access below.
On small screens the block folds into a menu button that opens a panel, unless On small screens is set to inline, which keeps the links on show. The slot at the end, After the links, takes things like an account icon, a basket icon or a button.
A hero is the large band at the top of a page. There are four, under Hero. Simple hero is a band of colour. Image hero puts text over a photo, with an overlay to keep the text readable. Split hero puts text beside a picture. Full-screen hero is a photo behind a Centre slot that takes any blocks, such as a logo, a heading and a tagline, optionally on a tinted or solid panel.
The simple, image and split heroes share their copy fields: Eyebrow (a short line above the heading), Heading, Kicker lines, Text, an Accent rule and up to three Calls to action, each with a Label, Link, Style and Size. Content width sets how wide that copy may be, and a slot below holds anything else you drop in. Every hero has the same frame fields: Padding, Width, Alignment, Vertical position, Height, Background and Text colour.
Height offers Auto (the content's own height, the default), Medium, Large, Half screen, Fill screen below nav and Full screen, and it can differ by screen size. Fill screen below nav ends the band exactly at the bottom of the window, whatever height the header is, which suits the opening band of a home page. In the editor's preview it shows as a full screen.
To make a slideshow, add two or more pictures under Photos (Pictures, in a Split hero). More fields appear: Transition, Seconds per photo, Controls and a Pause button. Keep the pause button on, because moving pictures need a way to stop them.
A developer can add a hero of the site's own with pnpm cms generate hero Splash. It is listed under Hero as “Custom: Splash”.
A list repeats one design for many items: posts, products, your orders, or the items of a collection you define yourself.
On the live site the list shows the current items. In the editor you see one sample item. A Slider can move by itself: Auto slide every sets the seconds between moves, 0 turns it off. It waits while a mouse is over it or keyboard focus is inside it, and its Pause button, on by default, lets a visitor stop it. The arrows can be restyled: Arrow style, shape, size, colour, icon, and position under the track or at its sides. Page through the items adds previous and next links under Columns and Rows lists.
A developer can add a source of the site's own, such as a team read from a JSON file, with pnpm cms generate collection team.
Click an empty part of the preview and use the Access field. The choices are Everyone, Signed in, Editors and admins, and Admins. A site with membership also offers “Only these groups”. The checkbox “Signed out visitors only” shows a page only to people who are not signed in. Access takes effect when you publish.
A visitor who is not signed in is sent to the sign-in page and brought back afterwards. A signed-in visitor whose role falls short sees a notice inside the site's layout in place of the page. Pages and posts can be locked. System pages, layouts, templates and emails cannot.
On a page, Also protect every page under this one locks the pages nested beneath it too, now and in future. Without it, each page keeps its own Access. A locked page is never listed for anyone: it stays out of the page menu, the sitemap, post lists and the public API. Link to it from a menu, the account page or a members page of your own, and let the page itself do the gating.
Individual blocks can be limited as well, with the Show to field at the end of a block's fields. Accounts and sign-in covers who can sign in and how roles work.
Theme changes colours, fonts and spacing for the whole site. Search engines covers titles, descriptions and the sitemap. Collections lets you keep lists of your own, and Your own blocks is for developers who want blocks that do not exist yet.