DocsIntegrating PuckMulti-column Layouts

Multi-column Layouts

Puck supports nested and multi-column layouts across any CSS layout using the <DropZone> component.

Nested components

Add the <DropZone> component to your render function to create a zone that you can drop components into.

import { DropZone } from "@measured/puck";
 
const config = {
  components: {
    Example: {
      render: () => {
        return (
          <div>
            <DropZone zone="my-content" />
          </div>
        );
      },
    },
    Card: {
      render: () => <div>Hello, world</div>,
    },
  },
};
Interactive Demo
Nested components example

Fixed layouts

Combine multiple DropZones to achieve fixed layouts. By default, components inside a DropZone are arranged along the vertical (block) axis.

import { DropZone } from "@measured/puck";
 
const config = {
  components: {
    Example: {
      render: () => {
        return (
          <div
            style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }}
          >
            <DropZone zone="left-column" />
            <DropZone zone="right-column" />
          </div>
        );
      },
    },
    Card: {
      render: ({ text }) => <div>{text}</div>,
    },
  },
};
Interactive Demo
Fixed layout example

Fluid layouts

Apply the CSS display property to a DropZone via the style or className props to arrange your components in different layouts. Puck supports drag-and-drop for all display values, including grid and flex.

import { DropZone } from "@measured/puck";
 
const config = {
  components: {
    Example: {
      render: () => (
        <DropZone
          zone="my-content"
          // Use CSS grid in this DropZone
          style={{ display: "grid", gridTemplateColumns: "2fr 1fr", gap: 16 }}
        />
      ),
    },
    Card: {
      render: ({ text }) => <div>{text}</div>,
    },
  },
};
Interactive Demo
Fluid layout using CSS grid

Removing the wrapper

By default, Puck will wrap your components in a div element. For some layouts, you may need to eliminate the wrapping element and treat the child component as a direct descendant of its’ parent DropZone.

For example, this is required if you wish to use CSS rules like flex-grow, grid-column, or grid-row.

Use the inline component parameter to remove the wrapping element. When using this API, you must also specify which element is draggable by passing the puck.dragRef prop to your element’s ref prop.

import { DropZone } from "@measured/puck";
 
const config = {
  components: {
    Example: {
      render: () => (
        <DropZone
          zone="my-content"
          style={{
            display: "grid",
            gridTemplateColumns: "1fr 1fr 1fr 1fr",
            gridTemplateRows: "1fr 1fr 1fr 1fr",
            gap: 16,
          }}
        />
      ),
    },
    Card: {
      inline: true, // Enable inline mode, removing the Puck wrapper
      render: ({ text, spanCol, spanRow, puck }) => (
        <div
          ref={puck.dragRef} // Let Puck know this element is draggable
          style={{
            gridColumn: `span ${spanCol}`,
            gridRow: `span ${spanRow}`,
          }}
        >
          {text}
        </div>
      ),
    },
  },
};
Interactive Demo
Advanced grid example

Restricting components

Use the allow and disallow DropZone props to restrict which components can be dragged into a DropZone.

import { DropZone } from "@measured/puck";
 
const config = {
  components: {
    Example: {
      render: () => {
        return (
          <div>
            <DropZone zone="my-content" allow={["Card"]} />
          </div>
        );
      },
    },
  },
};

Combine this with categories to restrict behavior based on your existing groups:

import { DropZone } from "@measured/puck";
 
const config = {
  categories: {
    typography: {
      components: ["Card"],
    },
  },
  components: {
    Example: {
      render: () => {
        return (
          <div>
            <DropZone
              zone="my-content"
              allow={categories.typography.components}
            />
          </div>
        );
      },
    },
  },
};

Further reading