Installation & Setup
There is nothing to install. LayoutBlocks is a copy-paste library — you browse a block, copy its files into your project, and register it with Payload. This page walks you through the full process.
Before You Start
Container Width
Blocks are designed for a max-width of 1536px with 2rem horizontal padding. This matches the 2xl breakpoint in Tailwind and gives blocks enough room to breathe on large screens while staying centered and readable.
Make sure your Tailwind config includes this container setup:
1// tailwind.config.ts
2container: {
3 center: true,
4 padding: '2rem',
5 screens: {
6 DEFAULT: '100%',
7 '2xl': '1536px',
8 },
9},If you started from the Payload website template, this is already configured. If your project uses a different container width, blocks will still work but may need spacing or layout adjustments.
Check Block Dependencies
Each block page lists its dependencies. Before copying a block, check if you need to install anything. Common dependencies include:
- lucide-react — icons used in some blocks
- shadcn/ui components — Badge, Accordion, etc.
- Media component — for rendering uploaded images (from the Payload website template)
- Modified link field — an opinionated improvement on the Payload website template's link field
Adding a Block: Step by Step
We will use Hero 1 as an example. The process is the same for every block.
Step 1: Copy the Block Files
Each block has two files you need: config.ts (the Payload block configuration) and component.tsx (the React component that renders it).
Create a folder for the block in your project. We recommend organizing by category so blocks are easy to find as your collection grows:
1src/blocks/
2├── heros/
3│ └── hero-1/
4│ ├── config.ts
5│ └── component.tsxGo to the block's page on LayoutBlocks, open the Code section, and copy both files into your project.
Step 2: Register the Block Config in Payload
Payload needs to know about your block so it appears in the admin panel's block picker. Import the block config and add it to a blocks field on your collection (usually Pages):
1import type { Block, CollectionConfig } from 'payload';
2import { Hero1Config } from '@/blocks/heros/hero-1/config';
3
4const Pages: CollectionConfig = {
5 slug: 'pages',
6 fields: [
7 {
8 name: 'layout',
9 type: 'blocks',
10 blocks: [Hero1Config],
11 },
12 ],
13};After adding the config, Payload will show the block in the admin panel when editors add blocks to a page.
What is a
blocksfield? In Payload, ablocksfield is a flexible content area where editors can add, reorder, and remove different block types. Each block type has its own set of fields. Think of it as a page builder. See the Payload blocks field docs for more.
Step 3: Render the Block on the Frontend
When Payload stores a page, each block in the layout array has a blockType property that tells you which block it is. You need a renderer component that maps block types to their React components:
1import type { Hero1Type } from '@/payload-types';
2import Hero1Component from '@/blocks/heros/hero-1/component';
3
4const blockComponents: Record<string, React.FC<any>> = {
5 hero1Config: Hero1Component,
6};
7
8export function RenderBlocks({ blocks }: { blocks: (Hero1Type | any)[] }) {
9 return blocks?.map((block, i) => {
10 const Component = blockComponents[block.blockType];
11 if (!Component) return null;
12 return <Component key={i} {...block} />;
13 });
14}The key in blockComponents must match the block's config slug. For Hero 1, the config has slug: 'hero1Config', so you use hero1Config as the key. When Payload stores page data, it saves this slug as the blockType property on each block — that is how block.blockType maps to the right component.
As you add more blocks, you add more entries to blockComponents. That is all there is to it.
Step 4: Generate TypeScript Types
After adding a new block config, run:
1pnpm payload generate:typesThis regenerates payload-types.ts with typed interfaces for your new block, giving you full autocomplete and type safety in your component.
Dependencies & Helpers
Modified Fields
Some blocks use opinionated improvements on the standard Payload link and linkGroup fields. These add a localizedLabel option (for i18n support) and a required option that the originals lack. We made these changes because multi-language projects need localized link labels, and form validation is cleaner when you can mark link fields as required at the field level.
- Link field — adds
localizedLabelandrequiredprops - Link Group field — adds
localizedLabelprop
If a block lists "link field (modified)" as a dependency, you need to copy this modified field into your project too.
CMSLink Component
Blocks render links using the CMSLink component from the Payload website template. This component handles both internal (relationship) and external (URL) link types that Payload's link field produces. If you started from the website template, you already have it.
The cn Utility
Blocks use cn() for conditional class name merging. This is a small utility that combines clsx (conditional classes) and tailwind-merge (deduplicates conflicting Tailwind classes). It comes with shadcn/ui — if you have shadcn set up, you have cn.