Puck is the open-source visual editor for React built by Measured - a self-hosted alternative to builder.io, WordPress and other WYSIWYG tools.
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
object
field type. -
DropZone restrictions: The new
allow
anddisallow
props 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
ui
prop: Set the initial UI state for the Puck editor on render. -
Add search to external fields: Show a search input in the
external
field 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.
Top comments (2)
This application is outrageously incredible! Kudos to the Measured team for creating this and sharing it. Phenomenal work guys. Now I just HAVE to work out a project so I can use it :)
Thanks for the kind words @paulharvey!
If you need any help, hit us up on Discord.