GridStack React Library - v13.0.0
    Preparing search index...

    GridStack React Library - v13.0.0

    React wrapper

    The React wrapper lives in projects/lib/src/ and is published with the main gridstack package as gridstack/dist/react (same idea as gridstack/dist/angular).

    Live demo app: cd react && yarn && yarn dev.

    See DESIGN-DECISIONS.md for architecture (static callbacks, portals, save/restore).


    Use <GridStack> with options and optional components for dynamic widget types.

    CSS

    @import "gridstack/dist/gridstack.css";

    .grid-stack {
    background: #fafad2;
    }
    .grid-stack-item-content {
    text-align: center;
    background-color: #18bc9c;
    }

    TSX

    import { GridStackOptions } from "gridstack";
    import { GridStack } from "gridstack/dist/react";

    const options: GridStackOptions = {
    margin: 8,
    cellHeight: 50,
    column: 12,
    children: [
    { id: "1", x: 0, y: 0, w: 2, h: 2, content: "Plain HTML item" },
    ],
    };

    export function Board() {
    return <GridStack options={options} />;
    }

    Put a component key on each child widget and pass a components map (like Angular dynamic selector types).

    import { GridStackOptions } from "gridstack";
    import { GridStack } from "gridstack/dist/react";

    function Text({ text }: { text: string }) {
    return <div>{text}</div>;
    }

    const options: GridStackOptions = {
    column: 12,
    cellHeight: 50,
    children: [
    { id: "a", x: 0, y: 0, w: 2, h: 2, component: "Text", props: { text: "Hello" } },
    ],
    };

    export function Board() {
    return <GridStack options={options} components={{ Text }} />;
    }

    useGridStack() must be used inside <GridStack> (e.g. in a child component). It exposes grid, addWidget, removeWidget, save, etc.

    React children of <GridStack> are rendered after the grid’s .grid-stack root in the DOM, so host UI (toolbars, debug readouts) appears below the grid instead of sharing the absolutely positioned canvas.

    import { GridStack } from "gridstack/dist/react";
    import { useGridStack } from "gridstack/dist/react";

    function Toolbar() {
    const { addWidget } = useGridStack();
    return (
    <button
    type="button"
    onClick={() =>
    addWidget?.({
    id: "new-" + Date.now(),
    w: 2,
    h: 2,
    x: 0,
    y: 0,
    component: "Text",
    props: { text: "Added" },
    })
    }
    >
    Add
    </button>
    );
    }

    export function Board() {
    return (
    <GridStack options={options} components={{ Text }}>
    <Toolbar />
    </GridStack>
    );
    }

    Render several <GridStack> instances (e.g. with acceptWidgets: true) to drag between grids—same pattern as Angular.


    Use subGridOpts.children on a widget; nested grids use the same components map from the parent <GridStack>.


    const { grid, save } = useGridStack();

    const json = JSON.stringify(save?.(true, false)); // widget list
    // later:
    grid?.load(JSON.parse(json));

    Optional: useWidgetSerializer inside a widget component merges extra fields into props on save.


    Legacy New
    <GridStackProvider> + <GridStackRenderProvider> + <GridStackRender> Single <GridStack options={...} components={...}>
    content: JSON.stringify({ name, props }) component + props on the widget
    useGridStackContext() useGridStack()

    The old files have been moved to react/lib/_old/ for reference and are excluded from the bundle.


    By default GridStack uses the item's outer .grid-stack-item-content div as the drag handle. If you set a custom draggable.handle that lives inside your React component, call grid.refreshDragHandles(el) after the content renders so GridStack can re-scan and attach listeners to the new handle element.

    import { useEffect, useRef } from "react";
    import { useGridStack } from "gridstack/dist/react";

    function MyWidget() {
    const { grid } = useGridStack();
    const handleRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
    if (!handleRef.current) return;
    const itemEl = handleRef.current.closest(".grid-stack-item") as HTMLElement | null;
    if (itemEl) grid?.refreshDragHandles(itemEl);
    }, [grid]);

    return (
    <div>
    <div ref={handleRef} className="my-drag-handle" style={{ cursor: "grab", padding: 8 }}>
    ☰ drag here
    </div>
    <p>content</p>
    </div>
    );
    }

    // Grid must be initialised with draggable.handle pointing at the same selector:
    const options: GridStackOptions = {
    draggable: { handle: ".my-drag-handle" },
    children: [{ id: "a", x: 0, y: 0, w: 3, h: 2, component: "MyWidget" }],
    };

    export function Board() {
    return <GridStack options={options} components={{ MyWidget }} />;
    }

    refreshDragHandles is called automatically by <GridStackItem> after each portal render, so the above pattern is only needed when you manage the item element yourself (e.g. via useGridStack().grid directly).


    Uses the TypeScript project projects/lib/tsconfig.build.json (ESM .js + .d.ts).

    From the repo root:

    yarn build:react
    

    Or from react/:

    yarn build:lib
    

    Output: dist/react/ at the repository root (alongside dist/angular/), so published gridstack npm tarball includes it via the files field.