DocsExtending PuckUI Overrides

UI overrides

💡

The overrides API is highly experimental and is likely to experience breaking changes.

Overrides allow you to change how Puck renders its default interface. It can be used with or without composition.

There are many different overrides available. See the overrides API reference for the full list.

Implementing an override

Use the overrides prop to implement an override:

import { Puck } from "@measured/puck";
 
export function Editor() {
  return (
    <Puck
      // ...
      overrides={{
        // Render a custom element for each item in the component list
        componentItem: ({ name }) => (
          <div style={{ backgroundColor: "hotpink" }}>{name}</div>
        ),
      }}
    />
  );
}

Examples

Custom publish button

A common use case is to override the Puck header. You can either use the header override to change the entire header, or use the headerActions override to inject new controls into the header and change the publish button.

Here’s an example that also leverage the internal Puck API to replace the default publish button with a custom one:

import { Puck, createUsePuck } from "@measured/puck";
 
const usePuck = createUsePuck();
 
const save = () => {};
 
export function Editor() {
  return (
    <Puck
      // ...
      overrides={{
        headerActions: ({ children }) => {
          const appState = usePuck((s) => s.appState);
 
          return (
            <>
              <button
                onClick={() => {
                  save(appState.data);
                }}
              >
                Save
              </button>
 
              {/* Render default header actions, such as the default Button */}
              {/*{children}*/}
            </>
          );
        },
      }}
    />
  );
}

Custom field type

An advanced use case is overriding all fields of a certain type by specifying the fieldTypes override.

import { Puck } from "@measured/puck";
 
export function Editor() {
  return (
    <Puck
      // ...
      overrides={{
        fieldTypes: {
          // Override all text fields with a custom input
          text: ({ name, onChange, value }) => (
            <input
              defaultValue={value}
              name={name}
              onChange={(e) => onChange(e.currentTarget.value)}
              style={{ border: "1px solid black", padding: 4 }}
            />
          ),
        },
      }}
    />
  );
}

Further reading