Docs
Integrating Puck
Component Configuration

Component Configuration

Puck's core behaviour is configured via the Config. This describes:

  • which components are available to Puck
  • how to render each component
  • which fields to show when the user selects a component
  • additional information, like category grouping

The Config is provided via the config prop to the main Puck components:

  • <Puck> reads the Config and renders an editor UI. The user interacts with the editor to produce a data payload.
  • <Render> walks a data payload and renders it according to the provided Config.

The render function

Components can be defined by via the components object in Config. Every definition must provide a render function:

const config = {
  components: {
    HeadingBlock: {
      render: () => {
        return <h1>Hello, world</h1>;
      },
    },
  },
};

This tells Puck that HeadingBlock is a valid component, and describes how to render it.

When the user drags the component onto the preview and hits Publish in the editor UI via the <Puck> component, this Config will produce a data payload like this:

{
  "content": [
    {
      "type": "HeadingBlock",
      "props": {
        "id": "HeadingBlock-1234"
      }
    }
  ],
  "root": {}
}

The data payload and Config together tell <Render> how to render the page. It can also be provided to <Puck> as an initial data payload.

TypeScript

If you're using TypeScript, we recommend strictly typing your config:

import type { Config } from "@measured/puck";
 
type Components = {
  HeadingBlock: {};
};
 
const config: Config<Components> = {
  components: {
    HeadingBlock: {
      render: () => {
        return <h1>Hello, world</h1>;
      },
    },
  },
};

Adding fields

Fields allow users to provide input to components. The value of each field is passed in as a prop to the render function.

You can define a field via the fields parameter:

const config = {
  components: {
    HeadingBlock: {
      fields: {
        title: {
          type: "text",
        },
      },
      render: ({ title }) => {
        return <h1>{title}</h1>;
      },
    },
  },
};

This will render a Text field when the user selects an instance of the HeadingBlock component in the editor UI.

Text field example

When the user modifies the input, the editor will produce a data payload like this:

{
  "content": [
    {
      "type": "HeadingBlock",
      "props": {
        "id": "HeadingBlock-1234",
        "title": "Hello, world"
      }
    }
  ],
  "root": {}
}

TypeScript

It's best to define the props for the component if using TypeScript. This enables strict type checking for your fields.

import type { Config } from "@measured/puck";
 
type Components = {
  HeadingBlock: {
    title: string;
  };
};
 
const config: Config<Components> = {
  // ...
};

Setting default props

Default props allow you to set an initial value for a prop when a new component is added.

Provide an object to the defaultProps parameter to configure this:

const config = {
  components: {
    HeadingBlock: {
      fields: {
        title: {
          type: "text",
        },
      },
      defaultProps: {
        title: "Hello, world",
      },
      render: ({ title }) => {
        return <h1>{title}</h1>;
      },
    },
  },
};

Unlike default parameters (opens in a new tab), defaultProps are stored in the data payload and will populate the Puck fields.

Text field example
Hello, world