Puck 0.13: Custom UIs, object fields & DropZone restrictions
2023-12-20 • Chris Villa
Puck v0.13.0 introduces some of our most powerful APIs yet, enabling completely custom interfaces, adding support for object fields and mechanisms to restrict DropZones.
TLDR
- Custom interfaces: Take complete control of the Puck UI with the new custom interface APIs.
 - Object fields: Represent objects as fields with the new 
objectfield type. - DropZone restrictions: The new 
allowanddisallowprops allow you to restrict which components can be dropped into DropZones. - New plugin API (Breaking Change): The plugin API has been updated to align with the new custom interfaces API. This is a breaking change. The plugin API remains experimental.
 - New transformProps API: The new transformProps API makes it easier to rename props on your components without breaking your payload.
 - New 
uiprop: Set the initial UI state for the Puck editor on render. - Add search to external fields: Show a search input in the 
externalfield modal, enabling the user to query your external API. 
Highlights
🎨 Custom interfaces
It's now possible to create completely custom Puck interfaces to integrate more deeply with your own UI and create a seamless experience for your users.
This can be achieved by passing children to the <Puck> component.
import { Puck } from "@measured/puck";
export function Editor() {
  return (
    <Puck>
      <div style={{ background: "hotpink" }}>
        <Puck.Preview />
      </div>
    </Puck>
  );
}
See this demo.
🪝 The usePuck hook
Access Puck's internals using the usePuck hook to extend Puck's functionality with powerful custom components.
import { Puck, usePuck } from "@measured/puck";
const JSONRenderer = () => {
  const { appState } = usePuck();
  return <div>{JSON.stringify(appState.data)}</div>;
};
export function Editor() {
  return (
    <Puck>
      <JSONRenderer />
    </Puck>
  );
}
🗃️ Object fields
Object fields enable you to represent your object types with the fields API. No more flattening your props!
const config = {
  components: {
    Example: {
      fields: {
        params: {
          type: "object",
          objectFields: {
            title: { type: "text" },
          },
        },
      },
      render: ({ params }) => {
        return <p>{params.title}</p>;
      },
    },
  },
};
🙅 DropZone restrictions
Restrict which components can be passed into a DropZone component with the allow and disallow props.
const MyComponent = () => (
  <DropZone zone="my-content" allow={["HeadingBlock"]} />
);
Deprecations
renderHeader deprecated
The renderHeader prop has been deprecated in favor of the overrides API.
// Before
export function Editor() {
  return (
    <Puck
      renderHeader={({ appState, dispatch }) => ()}
    />
  );
}
// After
export function Editor() {
  return (
    <Puck
      overrides={{
        header: ({ appState, dispatch }) => ()
      }}
    />
  );
}
renderHeaderActions deprecated
The renderHeaderActions prop has been deprecated in favor of the overrides API.
// Before
export function Editor() {
  return (
    <Puck
      renderHeaderActions={({ appState, dispatch }) => ()}
    />
  );
}
// After
export function Editor() {
  return (
    <Puck
      overrides={{
        headerActions: ({ appState, dispatch }) => ()
      }}
    />
  );
}
Breaking changes
renderComponentList removed
The renderComponentList prop has been removed in favor of the overrides API.
// Before
export function Editor() {
  return (
    <Puck
      renderComponentList={({ appState, dispatch }) => ()}
    />
  );
}
// After
export function Editor() {
  return (
    <Puck
      overrides={{
        componentList: ({ appState, dispatch }) => ()
      }}
    />
  );
}
Plugin API revamped
The plugin API has been significantly revamped to match the overrides API.
// Before
export function Editor() {
  return (
    <Puck
      plugins={[
        { renderFields: ({ appState, dispatch }) => () }
      ]}
    />
  );
}
// After
export function Editor() {
  return (
    <Puck
      plugins={[
        overrides: {
          form: ({ appState, dispatch }) => ()
        }
      ]}
    />
  );
}
Changelog
See the GitHub release for a full changelog.