DocsIntegrating PuckRoot Configuration

Root Configuration

The root is the top-level component within Puck. It:

  1. Renders a single wrapper around your other components. This can be overwritten with a render function.
  2. Stores meta data, like the page title. This can be extended with fields.

Configuring the root is similar to configuring components.

The root render function

Use the root parameter to specify a render function:

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

The root render function will wrap all of the components. children is a node containing the nested components.

If you don’t render children, your components will not be rendered (unless you’re defining custom root DropZones).

Example output

Given a minimal data payload containing one HeadingBlock

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

the example config will render HTML nodes like this:

<!-- root render -->
<div>
  <!-- HeadingBlock render -->
  <h1>Hello, world</h1>
 
  <!-- Remining nodes -->
</div>

Adding fields

Root fields provide user input to the root render method, and can be used to store metadata.

By default, root is configured with a title text field:

const config = {
  // ...
  root: {
    render: ({ children, title }) => {
      return (
        <div>
          <h1>{title}</h1>
          {children}
        </div>
      );
    },
  },
};

We can override the default field configuration by providing custom Fields to the fields parameter:

const config = {
  // ...
  root: {
    fields: {
      title: { type: "text" }, // We need to redefine the `title` field if we want to retain it
      description: { type: "textarea" },
    },
    render: ({ children, title, description }) => {
      return (
        <div>
          <h1>{title}</h1>
          <p>{description}</p>
          {children}
        </div>
      );
    },
  },
};

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

{
  "content": [
    // ...
  ],
  "root": {
    "props": {
      "title": "Hello, world",
      "description": "Lorem ipsum"
    }
  }
}

TypeScript

Generic types can be passed to the Config type to strictly type your root configuration:

import type { Config } from "@measured/puck";
 
type RootProps = {
  description: string;
};
 
const config: Config<{}, RootProps> = {
  // ...
};

Setting default props

Provide an object to the defaultProps parameter to configure default props for the root fields:

const config = {
  // ...
  root: {
    fields: {
      title: { type: "text" },
      description: { type: "textarea" },
    },
    defaultProps: {
      title: "Hello, world",
      description: "Lorem ipsum",
    },
    render: ({ children, title, description }) => {
      return (
        <div>
          <h1>{title}</h1>
          <p>{description}</p>
          {children}
        </div>
      );
    },
  },
};

Unlike default parameters, defaultProps are stored in the data payload and will populate the Puck fields.