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>,
},
},
};
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>,
},
},
};
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>,
},
},
};
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>
),
},
},
};
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>
);
},
},
},
};