Skip to Content
Delmare Digital
Components

Custom components

Build your own Puck components from the built-in configs and field factories, in editor and server variants.

The plugin exports every built-in component config and every field factory, so you can build a Puck configuration from just the pieces you want and add components of your own.

Cherry-picking components

Import only the components you need from @delmaredigital/payload-puck/components:

puck/config.editor.ts
import type { Config } from '@puckeditor/core'
import {
  SectionConfig,
  HeadingConfig,
  TextConfig,
  ImageConfig,
  ButtonConfig,
} from '@delmaredigital/payload-puck/components'

export const puckConfig: Config = {
  components: {
    Section: SectionConfig,
    Heading: HeadingConfig,
    Text: TextConfig,
    Image: ImageConfig,
    Button: ButtonConfig,
  },
  categories: {
    layout: { components: ['Section'] },
    content: { components: ['Heading', 'Text', 'Image', 'Button'] },
  },
}

The available configs are ContainerConfig, FlexConfig, GridConfig, ColumnsConfig, SectionConfig, SpacerConfig, TemplateConfig, HeadingConfig, TextConfig, RichTextEditorConfig, RichTextConfig, ImageConfig, ButtonConfig, CardConfig, DividerConfig and AccordionConfig. AnimatedWrapper is exported for wrapping your own components in the entrance animations.

Using field factories

Build a component with the plugin's custom fields:

components/Hero.tsx
import type { ComponentConfig } from '@puckeditor/core'
import {
  createMediaField,
  createBackgroundField,
  createPaddingField,
  backgroundValueToCSS,
  paddingValueToCSS,
} from '@delmaredigital/payload-puck/fields'

export const HeroConfig: ComponentConfig = {
  label: 'Hero',
  fields: {
    image: createMediaField({ label: 'Background Image' }),
    overlay: createBackgroundField({ label: 'Overlay' }),
    padding: createPaddingField({ label: 'Padding' }),
  },
  defaultProps: {
    image: null,
    overlay: null,
    padding: { top: 80, bottom: 80, left: 24, right: 24, unit: 'px', linked: false },
  },
  render: ({ image, overlay, padding }) => (
    <section
      style={{
        ...backgroundValueToCSS(overlay),
        padding: paddingValueToCSS(padding),
      }}
    >
      {/* Hero content */}
    </section>
  ),
}

A fuller example, a banner with variants, colour pickers and padding, is in the starter files.

Server and editor variants

PageRenderer needs a server-safe configuration. Read the built-in server configs from baseConfig:

components/PublishedPage.tsx
import type { Config, Data } from '@puckeditor/core'
import { baseConfig } from '@delmaredigital/payload-puck/config'
import { PageRenderer } from '@delmaredigital/payload-puck/render'

const renderConfig: Config = {
  ...baseConfig,
  components: {
    Section: baseConfig.components.Section,
    Heading: baseConfig.components.Heading,
    Text: baseConfig.components.Text,
  },
  categories: {},
}

export function PublishedPage({ data }: { data: Data }) {
  return <PageRenderer config={renderConfig} data={data} />
}

The /components entry point has a 'use client' directive, including its *ServerConfig exports. Importing those exports in a Server Component gives you client references, which PageRenderer cannot read as component configs. Use /config as above; individual server files are not exposed as package entry points.

For a custom component that uses hooks or client-only code, write two files:

MyComponent.tsx
MyComponent.server.tsx
  • MyComponent.tsx: the full editor version, with fields and interactivity.
  • MyComponent.server.tsx: the server-safe version, with no hooks and no 'use client'.

Register the editor version in your editor config and the server version in your render config, under the same key.

Next

To add your components to the built-in set rather than starting from scratch, see Extending configs.

Edit this page on GitHub

On this page