Docking layouts for React that you own.
dashfoo gives React tool builders tabs, nested splits, drag-docking, and in-app
floating panels. The whole arrangement is a JSON-serializable model. Start with
DashfooLayout, or compose the chrome from Layout and Tabset parts.
MIT licensed · early-adopter release · React 18.3.1 and 19 · ESM only
Try the demo · Documentation · Website · Issues and questions
npm install @dashfoo/core @dashfoo/react @dashfoo/theme
# or
pnpm add @dashfoo/core @dashfoo/react @dashfoo/themeimport { model, row, tab, tabset } from "@dashfoo/core";
import { DashfooLayout } from "@dashfoo/react";
import "@dashfoo/react/styles.css";
import "@dashfoo/theme/dashfoo.css";
const layout = model(
row(
[
tabset([tab("chart", "Chart"), tab("notes", "Notes")], { id: "main" }),
tabset([tab("activity", "Activity")], { id: "side" }),
],
{ id: "root" },
),
);
export const Dashboard = () => (
<div style={{ height: "100dvh" }}>
<DashfooLayout
defaultModel={layout}
factory={(node) => <p>{node.name} content</p>}
floatable
responsive={{ maxWidth: 720 }}
/>
</div>
);Give the mount chain a height and remove scaffold CSS that constrains #root:
html,
body,
#root {
height: 100%;
margin: 0;
}Use the complete getting-started guide,
or copy the standalone Vite or Next.js starter.
In Next.js, define factories and registries in a "use client" module.
| Capability | Details |
|---|---|
| Docking | Move tabs or whole tabsets; stack, reorder, or split in four directions. Drag external widgets into the layout. |
| Sizing | Nested rows and columns, proportional weights, min/max constraints, magnetic split snapping. |
| Floating panels | Move, resize, rename, minimize, and dock back within the same app. Drag tabs into and out of floats. |
| State | Controlled or uncontrolled state, action interception, imperative controls, undo/redo in uncontrolled mode. |
| Persistence | Validated JSON, pluggable synchronous storage, debounced writes, restore after hydration. |
| Composition | Use the complete component, slots, or public Layout/Tabset parts to arrange your own chrome. |
| Appearance | Structural positioning styles only; supply a skin or use the optional light/dark theme and its tokens. |
| Adaptive layouts | Stack and lock restructuring at a breakpoint while retaining the desktop arrangement. |
| Content lifecycle | Inactive content unmounts by default. keepMounted retains state across tab switches. |
Tab content never lives in the model: component is a registry key. Provide a
components registry or factory to render it. Use unique ids when reusing a
component key. State that must survive moving between tabsets belongs outside
individual panel components.
Use dashfoo for editors, terminals, internal tools, and dashboards whose users need to arrange their workspace. A simple two-pane split may only need react-resizable-panels. A freeform coordinate grid is a different model; consider react-grid-layout.
Docking is pointer-only. Tabs support arrow-key selection and the exposed buttons support keyboard activation, but this release has no keyboard docking or native browser-window popouts. Floating panels stay in the same document. Responsive mode disables restructuring below its configured width. There is no broad WCAG conformance claim for arbitrary consumer-built chrome.
This release is for early adopters. APIs can evolve; the persisted schema is
currently version 1, with no built-in migration machinery. Controlled mode
requires application-owned history. Widget state is separate from layout persistence.
| Package | Purpose | Reference |
|---|---|---|
@dashfoo/core |
Framework-free schemas, builders, reducer, geometry, history, serialization, and state machines. | API |
@dashfoo/react |
Layout, compound parts, hooks, persistence, and drag/resize adapters. | API |
@dashfoo/theme |
Prebuilt CSS, a Tailwind v4 entry, and overridable design tokens. | API |
React and React DOM are peers. Zod, XState, dnd-kit, react-resizable-panels, and Zustand are installed transitively as package dependencies. They are not all bundled into the published JavaScript; your application bundler resolves them. Core exports its state machines for lower-level integrations. The React-facing layout/store API does not require primitive instances.
Requires Node 24+ and pnpm 11.
pnpm install
pnpm dev
pnpm verify
pnpm format:check
pnpm fallow:dead
pnpm --filter demo-vite test:e2e
pnpm --filter docs test:e2e
pnpm test:consumersSee CONTRIBUTING, support, and the
launch checklist. Canonical guides live in
apps/docs/content/docs; package READMEs describe the public API.
MIT, Pedro Filho.