Docs
Integrating Puck
Dynamic Props

Dynamic Props

Dynamic prop resolution allows you to change the props for a component after the props have been changed by the user. This is useful for making third-party API calls, such as requesting the latest content from a headless CMS.

Dynamic component props

The resolveData function allows you to make changes to the props and set fields as read-only.

For example, we can set the value of one prop to another:

const config = {
  components: {
    HeadingBlock: {
      fields: {
        title: {
          type: "text",
        },
        resolvedTitle: {
          type: "text",
        },
      },
      resolveData: async ({ props }) => {
        return {
          props: {
            resolvedTitle: props.title,
          },
        };
      },
      render: ({ resolvedTitle }) => {
        return <h1>{resolvedTitle}</h1>;
      },
    },
  },
};
Try changing the "title" field

Setting fields as read-only

resolveData also allows us to mark fields as read-only using the readOnly parameter.

const config = {
  components: {
    HeadingBlock: {
      // ...
      resolveData: async ({ props }) => {
        return {
          props: {
            resolvedTitle: props.title,
          },
          readOnly: { resolvedTitle: true },
        };
      },
      // ...
    },
  },
};
The resolvedTitle field is locked

Preventing duplicate calls

It's possible that resolveData may carry out an expensive operation (like an API call) that we want to avoid making unless a specific prop has changed.

This can be restricted by checking the changed param before calling any expensive operations.

const config = {
  components: {
    HeadingBlock: {
      // ...
      resolveData: async ({ props }, { changed }) => {
        if (!changed.text) return { props };
 
        return {
          props: {
            resolvedTitle: await expensiveOperation(props.title),
          },
        };
      },
      // ...
    },
  },
};

Dynamic Root props

The resolveData method is also available on the root component.

const config = {
  components: {},
  root: {
    fields: {
      title: {
        type: "text",
      },
      resolvedTitle: {
        type: "text",
      },
    },
    resolveData: async ({ props }) => {
      return {
        props: {
          resolvedTitle: props.title,
        },
      };
    },
    render: ({ children, resolvedTitle }) => {
      return (
        <>
          <h1>{resolvedTitle}</h1>
          {children}
        </>
      );
    },
  },
};

Triggering resolveData

Resolve data is triggered whenever the props for a component change, or when the resolveAllData utility is used.

import { resolveAllData } from "@measured/puck";
 
const updatedData = await resolveAllData(data, config);

Further reading