Custom Fields
Puck can be extended with completely custom fields for different use-cases.
Creating a custom field
Creating a custom field is possible using the custom field type:
const config = {
components: {
Example: {
fields: {
title: {
type: "custom",
render: ({ name, onChange, value }) => (
<input
defaultValue={value}
name={name}
onChange={(e) => onChange(e.currentTarget.value)}
style={{ border: "1px solid black", padding: 4 }}
/>
),
},
},
render: ({ title }) => {
return <p>{title}</p>;
},
},
},
};The onChange function updates the Puck data payload for the field name, in this case “title”.
Adding a label
You can add your own label, but it’s recommended to use the <FieldLabel> component provided by Puck to seamlessly integrate into the Puck field UI.
import { FieldLabel } from "@measured/puck";
const config = {
components: {
Example: {
fields: {
title: {
type: "custom",
label: "Label Example",
render: ({ field }) => (
<FieldLabel label={field.label}>
<input {/*...*/} />
</FieldLabel>
),
},
},
// ...
},
},
};Rendering Puck fields internally
Use the <AutoField> component to render Puck fields within your custom field.
import { AutoField } from "@measured/puck";
const config = {
components: {
Example: {
fields: {
title: {
type: "custom",
label: "Label Example",
render: ({ field, value, onChange }) => (
<FieldLabel label={field.label}>
<AutoField
field={{ type: "text" }}
onChange={(value) => onChange(value)}
value={value}
/>
</FieldLabel>
),
},
// ...
},
},
},
};Updating the UI state
The onChange function can also be used to modify the Puck UI state at the same time as updating the field value:
const config = {
components: {
Example: {
fields: {
title: {
type: "custom",
render: ({ name, onChange, value }) => (
<input
defaultValue={value}
name={name}
onChange={(e) =>
onChange(
e.currentTarget.value,
// Close the left side bar when this field is changed
{ leftSideBarVisible: false }
)
}
style={{ border: "1px solid black", padding: 4 }}
/>
),
},
},
render: ({ title }) => {
return <p>{title}</p>;
},
},
},
};