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-reactStability
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
| requirement | why |
|---|---|
react and react-dom ^19 | peer dependencies of @fragiola/dockable-react. The primitives use React 19 features: ref as a plain prop and ref cleanup functions. |
| A browser DOM | the 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 modules | both 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/dockableimport { 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.