Skip to Content
Delmare Digital
Guides

Integrations

Add bundles of Puck components, categories and editor plugins from other packages, such as experiments on Puck slots.

An integration bundles Puck components, categories and optional editor plugins, so another package can add them to your configuration without you rebuilding it. Integrations need payload-puck 0.10.3 or later.

interface PuckIntegration {
  name: string
  components?: Record<string, ComponentConfig<any>>
  categories?: Config['categories']
  /** Editor only; ignored by render-side config helpers. */
  plugins?: readonly Plugin[]
}

How they merge

  • Components: your components win. An integration only fills component keys your config doesn't define; if two integrations define the same key, the first one wins. Each skipped component logs one warning in development.
  • Categories: your category fields win, and the integration's component names are appended without duplicates.
  • Plugins: editor plugins only. Config helpers such as extendConfig ignore them.

Adding an integration

Pass the same integrations to your render config and to the editor.

puck/config.server.tsx
// Render config
import { extendConfig, baseConfig, type PuckIntegration } from '@delmaredigital/payload-puck/config'

const integrations: readonly PuckIntegration[] = [{
  name: 'dummy',
  components: { DummyBlock: { render: () => <div>Dummy block</div> } },
  categories: { custom: { title: 'Custom', components: ['DummyBlock'] } },
}]

export const renderConfig = extendConfig({ base: baseConfig, integrations })
components/EditorProvider.tsx
'use client'

import { PuckConfigProvider, type PuckIntegration } from '@delmaredigital/payload-puck/client'
import { editorConfig } from '@delmaredigital/payload-puck/config/editor'
import type { ReactNode } from 'react'

const integrations: readonly PuckIntegration[] = [{
  name: 'dummy',
  components: { DummyBlock: { render: () => <div>Dummy block</div> } },
  categories: { custom: { title: 'Custom', components: ['DummyBlock'] } },
}]

export function EditorProvider({ children }: { children: ReactNode }) {
  return <PuckConfigProvider config={editorConfig} integrations={integrations}>{children}</PuckConfigProvider>
}

Create the integration array once, at module scope. A new array on every render rebuilds the editor config. PuckEditor also accepts integrations directly.

applyIntegrations(config, integrations) applies integrations to a config you already have. It and the PuckIntegration type are exported from /config, /config/editor and /client.

Plugins

Integration plugins run after plugins from the plugins prop and from PuckConfigProvider. A named integration plugin is skipped when a plugin with the same name came from the prop, the context or an earlier integration. plugins={false} disables all plugins, while integration components still apply.

Opting out

The editor applies integrations without exclude. To opt out of one integration component, leave that integration out of the provider, or define your own component under the same key, which wins.

Running experiments on slots

@delmaredigital/payload-experiments runs A/B experiments on Puck slots through an integration. It needs payload-experiments 0.4.0 or later with payload-puck 0.10.3 or later.

In outline: enable Puck in the experiments plugin, pass experimentsPuck() (from @delmaredigital/payload-experiments/puck) to extendConfig in your render config, and pass experimentsPuckEditor() (from @delmaredigital/payload-experiments/puck/editor) to PuckConfigProvider, created once at module scope. Its editor CSS goes in your editor stylesheet.

puck/config.server.tsx
import { extendConfig, baseConfig } from '@delmaredigital/payload-puck/config'
import { experimentsPuck } from '@delmaredigital/payload-experiments/puck'

export const renderConfig = extendConfig({ base: baseConfig, integrations: [experimentsPuck()] })
components/EditorProvider.tsx
'use client'
import { PuckConfigProvider } from '@delmaredigital/payload-puck/client'
import { editorConfig } from '@delmaredigital/payload-puck/config/editor'
import { experimentsPuckEditor } from '@delmaredigital/payload-experiments/puck/editor'

const integrations = [experimentsPuckEditor()]

export function EditorProvider({ children }: { children: React.ReactNode }) {
  return <PuckConfigProvider config={editorConfig} integrations={integrations}>{children}</PuckConfigProvider>
}

The full setup, including the plugin option, custom routes and the editor stylesheet import, is in the payload-experiments docs.

Edit this page on GitHub

On this page