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