Puck 0.19 achieves 10x performance improvement, adds programmatic nesting

4 months ago 18

Puck 0.19 introduces the Slots API, the powerful successor to DropZones that lets you nest components using a field. This new approach allows you to define drop areas and their content programmatically using and , enabling sophisticated patterns like component templates:

The Puck demo showcasing the template pattern

In addition to Slots, this release brings major performance improvements, a new metadata API for passing data into every component, and many quality-of-life upgrades.

In this post, we’ll walk through everything new in Puck 0.19 and how to start using it:

If you’re upgrading from a previous version, be sure to check the upgrade guide for breaking changes and migration tips.

You can also find detailed docs for each new feature in our documentation.

Slots API

The slots API is a new field type you can use to render drop zones and nest components, replacing the DropZone API.

It works like any other field: you define it in your component config, and get access to its value in the component function. The slot field is converted to a component that you can use to render the drop zone.

Flexbox component with slots

The slot component provided to the render function accepts most of the same props as the component, making migration straightforward. See the slots documentation for a full breakdown of all available render props.

The components inside a slot are stored within the props of the parent component as an array of , making slots completely portable and straightforward to work with for data transformation or schema validation.

Since slots are regular fields, you can take full advantage of other field APIs, like and , to programmatically set the components they contain.

Flexbox component with default props for slot fields

Slots are now the recommended way to handle nested components in Puck. The component has been deprecated and will be removed in a future release.

New function:

The new utility recursively walks all slots in the entire tree of the data payload or a single node, and optionally modifies the nodes.

Selectors for

Puck 0.19 introduces selectors for , letting you subscribe to the parts of the internal Puck API you need in order to avoid unnecessary re-renders. To use selectors, use the new helper, and pick which part of the API you want to listen to:

The original hook is still available and won’t be deprecated.

For a breakdown of how selectors compare with the original , check out the upgrade guide.

New hook:

To make it possible to access the internal Puck API outside of the render lifecycle, we’ve added a new hook called .

returns a function that can be called to fetch the latest Puck API without triggering re-renders.

For a breakdown of how compares with the original , check out the upgrade guide.

Metadata API

This was a contribution made by: @jsjexpert

The metadata API lets you inject data into every component within your config, without relying on context.

Metadata can also be accessed within resolveData:

New recipe:

This was a contribution made by: @matthewlynch

This version also includes a recipe for using Puck with the react-router framework, so you can scaffold new projects with everything pre-configured.

To use it, run and enter when asked:

Improved performance

A big focus for this release was performance. Puck 0.19 drastically reduces the number of unnecessary re-renders, making the editor significantly faster and smoother, especially in larger projects.

To demonstrate this, we compared rendering times for common actions in 0.19 vs 0.18.3 using Puck with a test page containing 20 components:

These were the results:

0.19 vs 0.18.3 rendering times comparison for standard puck actions in milliseconds

  • Inserting a was 82% faster in 0.19.
  • Replacing a prop was 91% faster in 0.19.
  • Reordering a was 79% faster in 0.19.
  • Deleting a was 63% faster in 0.19.

Getters for item selectors

The internal Puck API (accessed with and ) now includes a set of utilities to get component data from within the tree. These are useful when working with slots.

Trigger event in resolveData

now receives a trigger parameter that tells you why it ran, whether it was because Puck was loaded (“load”), the component was dropped in the canvas (”insert”), props were updated (“replace”), or you forced it via (“force”).

This gives you more control over how and when your data is resolved, so you can skip unnecessary fetches or run specific logic depending on the event.

Custom label icons for fields

This was a contribution made by: @DamianKocjan

You can now provide your own icons for field labels by passing a React node to the new config parameter. If you’re using the component directly, you can provide the icon via the prop.

A Puck text field with a custom Lucide "text cursor" label icon

Field placeholders

This was a contribution made by: @DamianKocjan

Fields now support placeholders for , , and fields.

To provide a placeholder, define the config parameter with the text you want to show.

 "Your company name here..."

Step size for number fields

This was a contribution made by: @shannonhochkins

You can now define a step value for fields to control how much the value increases or decreases when using the input or keyboard arrow buttons. See on MDN.

A Puck number field with a step size of two

Hiding fields

It’s now possible to hide fields from the UI by setting the field parameter to .

New type

The new type lets you type your root configuration with its expected props when using TypeScript. If you’ve broken up your config, this’ll help you keep everything type-safe.

New action

The action is now available in the Puck API , making it possible to update only the root data without using an expensive action.

Check out the upgrade guide for step-by-step instructions on upgrading to 0.19. It includes deprecated APIs, breaking changes, and common pitfalls.

See the full changelog for all changes via the GitHub release.

Read Entire Article