Your first grid
From a layout of plain objects to a dashboard that drags, resizes and pushes, then styled from outside.
This page builds the grid of the hello-grid example, step by step.
Describe the layout
A layout is an array of items in grid units: x and y are the first column and row, w and
h the width and height in columns and rows. id names each item.
import type { Layout } from "@fragiola/grid-layout-react";
export const layout: Layout = [
{ id: "revenue", x: 0, y: 0, w: 4, h: 2 },
{ id: "orders", x: 4, y: 0, w: 4, h: 2 },
{ id: "visitors", x: 8, y: 0, w: 4, h: 2 },
];Render the grid
Root takes the layout and the grid's measurements; Items hands you each item to render. The
item is yours: put anything inside.
import { GridLayout } from "@fragiola/grid-layout-react";
export function Dashboard() {
return (
<GridLayout.Root defaultLayout={layout} cols={12} rowHeight={64} gap={[12, 12]}>
<GridLayout.Items>
{(item) => (
<GridLayout.Item itemId={item.id} aria-label={item.id}>
{item.id}
</GridLayout.Item>
)}
</GridLayout.Items>
</GridLayout.Root>
);
}It already drags: press an item and move. It has no look: the next step gives it one.
Add a handle and a placeholder
A ResizeHandle is a side or corner the item is resized from; a Placeholder shows where the
held item would land. Neither has a look or a size of its own.
<GridLayout.Item itemId={item.id} aria-label={item.id} className="card">
{item.id}
<GridLayout.ResizeHandle side="bottom-end" aria-label={`Resize ${item.id}`} className="corner" />
</GridLayout.Item>
<GridLayout.Placeholder className="placeholder" />Style the parts
Every part takes className (a string, or a function of its state) and exposes its state as
data-* attributes.
.card { border: 1px solid #ddd; border-radius: 8px; background: white; cursor: grab; }
.card:not([data-dragging]) { transition: transform 160ms, width 160ms, height 160ms; }
.card[data-dragging] { cursor: grabbing; box-shadow: 0 12px 28px rgb(0 0 0 / 0.16); }
.corner { position: absolute; inset-inline-end: 0; bottom: 0; width: 14px; height: 14px; }
.placeholder { border: 2px dashed royalblue; border-radius: 8px; }Keep the changes
onLayoutChange tells you the layout after every committed change, once: never during a
gesture. Save it, or hold the layout in your state and pass it as layout.
const [layout, setLayout] = useState(start);
<GridLayout.Root layout={layout} onLayoutChange={setLayout}>…</GridLayout.Root>