Under active development — things may change.

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:

TypeScript
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:

Code
1src/blocks/
2├── heros/
3│   └── hero-1/
4│       ├── config.ts
5│       └── component.tsx

Go 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):

TypeScript
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 blocks field? In Payload, a blocks field 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:

TSX
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:

Terminal
1pnpm payload generate:types

This 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.

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.