Documentation
Getting started

Installation

Add Dockable to a React 19 app with one package, the React primitives, which bring the core with them.

A React app installs one package, @fragiola/dockable-react: the primitives, the hooks and the whole framework-agnostic core, re-exported.

pnpm add @fragiola/dockable-react

Stability

Dockable is 0.x: until 1.0, the API may break between minor versions (0.1 to 0.2), and the changelog says what changed and how to update.

Requirements

requirementwhy
react and react-dom ^19peer dependencies of @fragiola/dockable-react. The primitives use React 19 features: ref as a plain prop and ref cleanup functions.
A browser DOMthe engine measures elements with getBoundingClientRect and ResizeObserver. The model loads in plain Node (for tests or server-side JSON handling), but a layout renders only on the client.
ES modulesboth packages are ESM only ("type": "module").

@fragiola/dockable has zero runtime dependencies. @fragiola/dockable-react depends only on the core, at the exact same version (one copy of the core per page: a drag between layouts and windows relies on it), and on its React peers.

The core ships its own types, and is best used with TypeScript in strict mode: the layout JSON, the command payloads and each tab's data are typed by your registry (Typed data). Plain JavaScript works too; the model validates every command's payload at runtime either way.

What to import from where

Everything comes from @fragiola/dockable-react:

import {
    // the primitives (one namespace) and the hooks
    Dockable,
    useDockable,
    useModelState,
    // the core: the model, its types and helpers
    createModel,
    type LayoutJson,
    type TabOf,
} from "@fragiola/dockable-react";

The React package re-exports the whole core (createModel, Model, LayoutJson, TabOf, TabsetNode, RowNode, Middleware, veto, MAIN_LAYOUT, …), so the pages on the core API apply as they are: in a React app, import those names from @fragiola/dockable-react too.

Without React

The core is published on its own as @fragiola/dockable, for code that renders nothing: handling layout JSON on a server, a script or a test that runs no React, or an adapter for another framework.

pnpm add @fragiola/dockable
import { createModel, type LayoutJson } from "@fragiola/dockable";

A React app never needs it: it comes with @fragiola/dockable-react.

Server rendering

The layout needs the DOM: the engine measures the elements you render and positions the panels after every commit. In a server-rendering framework (Next.js, Remix, …), mount the layout on the client only. With Next.js, mark the file "use client" and load the component with next/dynamic and ssr: false, or render it behind a mounted guard. Pre-rendering the layout would produce markup without geometry and a hydration flash.

"use client";

import dynamic from "next/dynamic";

// the layout measures the DOM: never pre-render it
const Workbench = dynamic(() => import("./workbench"), { ssr: false });

export default function Page() {
    return <Workbench />;
}

Popout windows

If you use popouts, serve a host page for the new windows (default popout.html next to your app; the path is configurable with popoutURL). It can be an empty HTML document: the core writes everything it needs into it.

Next

Your first layout builds a working, typed layout step by step.