Split-screen visual of Puck editor interface and live web page preview with floating code snippets

Puck: Unleash Your React Components with Visual Editing Magic

The Orange Cat
The Orange Cat

Puck is an innovative open-source visual editor designed specifically for React applications. It bridges the gap between developers and content creators, offering a powerful drag-and-drop interface that works seamlessly with your existing React component library. Let’s dive into the world of Puck and discover how it can transform your content creation workflow.

What Sets Puck Apart?

Puck isn’t just another page builder – it’s a game-changer for React developers and content teams alike. Here’s why:

  • React-First Approach: Built from the ground up for React, ensuring seamless integration with your existing projects.
  • Component Flexibility: Use your own React components, maintaining full control over your design system.
  • Open-Source Freedom: Licensed under MIT, Puck is free to use in both personal and commercial projects.
  • Self-Hosted Solution: Avoid vendor lock-in by hosting Puck within your own infrastructure.
  • Headless CMS Compatibility: Easily integrate with your favorite headless CMS or use Puck as a standalone solution.
  • Extensibility: Enhance Puck’s functionality with a growing ecosystem of plugins and adapters.

Getting Started with Puck

Let’s walk through the process of adding Puck to your React project.

Installation

First, install Puck using npm:

npm install @measured/puck

For those starting a new project, Puck offers a convenient generator:

npm create puck-app

Basic Configuration

To use Puck, you’ll need to create a configuration file that defines your components and their editable properties. Here’s a simple example:

import type { Config } from "@measured/puck";

type Props = {
  HeadingBlock: { title: string };
};

export const config: Config<Props> = {
  components: {
    HeadingBlock: {
      fields: {
        title: { type: "text" },
      },
      defaultProps: {
        title: "Heading",
      },
      render: ({ title }) => (
        <div style={{ padding: 64 }}>
          <h1>{title}</h1>
        </div>
      ),
    },
  },
};

export default config;

This configuration defines a simple HeadingBlock component with an editable title field.

Rendering the Puck Editor

To render the Puck editor in your application, use the <Puck> component:

import { Puck } from "@measured/puck";
import "@measured/puck/puck.css";
import config from "./puck.config";

const initialData = {};
const save = (data) => {
  // Save logic here
};

export function Editor() {
  return <Puck config={config} data={initialData} onPublish={save} />;
}

Rendering Puck-Generated Content

To display the content created with Puck, use the <Render> component:

import { Render } from "@measured/puck";
import config from "./puck.config";

export function Page({ data }) {
  return <Render config={config} data={data} />;
}

Advanced Puck Features

Custom Fields

Puck allows you to create custom field types for more complex editing scenarios. Here’s an example of a custom color picker field:

import { Puck } from "@measured/puck";
import ColorPicker from "your-color-picker-component";

const config = {
  components: {
    ColorBlock: {
      fields: {
        color: {
          type: "custom",
          render: ({ onChange, value }) => (
            <ColorPicker color={value} onChange={onChange} />
          ),
        },
      },
      render: ({ color }) => (
        <div style={{ backgroundColor: color, height: 100, width: 100 }} />
      ),
    },
  },
};

Dynamic Fields

Use the resolveFields API to dynamically show or hide fields based on other prop values:

const config = {
  components: {
    ConditionalBlock: {
      fields: {
        type: { type: "select", options: ["text", "image"] },
      },
      resolveFields: ({ type }) => {
        if (type === "text") {
          return { content: { type: "text" } };
        } else {
          return { src: { type: "text" } };
        }
      },
      render: ({ type, content, src }) => (
        type === "text" ? <p>{content}</p> : <img src={src} alt="" />
      ),
    },
  },
};

Permissions API

Puck v0.16 introduced a powerful permissions API, allowing you to control which editing features are available:

<Puck
  config={config}
  data={data}
  permissions={{
    delete: false,
    duplicate: true,
    insert: (componentData) => componentData.type !== "RestrictedComponent",
  }}
/>

This example disables deletion, enables duplication, and restricts insertion of a specific component type.

Extending Puck

Plugins

Puck’s plugin system allows you to extend its functionality. For example, the heading-analyzer plugin helps ensure proper heading structure for accessibility:

import { Puck } from "@measured/puck";
import { headingAnalyzer } from "@measured/puck-plugin-heading-analyzer";

<Puck
  config={config}
  data={data}
  plugins={[headingAnalyzer()]}
/>

Custom Action Bars

Create tailored editing experiences by customizing the action bar for your components:

const config = {
  components: {
    CustomBlock: {
      fields: { /* ... */ },
      render: ({ /* ... */ }) => { /* ... */ },
      actionBar: ({ remove, duplicate }) => (
        <>
          <button onClick={remove}>Delete</button>
          <button onClick={duplicate}>Clone</button>
          <button onClick={() => console.log("Custom action")}>
            Custom Action
          </button>
        </>
      ),
    },
  },
};

Conclusion

Puck offers a powerful, flexible solution for creating visual editing experiences in React applications. By seamlessly integrating with your existing component library and offering extensive customization options, Puck empowers both developers and content creators to build dynamic, on-brand pages with ease.

Whether you’re building a marketing site, a content-heavy application, or a custom CMS, Puck provides the tools you need to create a tailored visual editing experience. Its open-source nature and growing community ensure that Puck will continue to evolve and improve, making it a solid choice for your next React project.

Give Puck a try in your next project, and experience the magic of visual editing with your own React components!

Comments