MIT-licensed · headless · zero imposed styling
Docking layouts for React that you own
dashfoo ships the structure: tabs, splits, drag-dock, and a serializable model. You keep the styling, so your dashboards match your product instead of a prebuilt skin.
app.yourproduct.com
What dashfoo gives you
dashfoo gives you FlexLayout’s power without the chrome you can’t restructure. State, mutations, and drag sit behind adapters you never touch.
- Headless by design
- The engine renders markup tagged with data-dashfoo attributes and applies no CSS. Style the chrome to match your product.
- One serializable model
- The whole layout is one plain, zod-validated object: your single source of truth. Save it, diff it, restore it, or send it over the wire.
- Real drag-docking
- Drag a tab to restack, split, reorder, or dock to an edge. Resizable splitters and maximize come built in, pointer-driven, with no config.
- Undo/redo & self-healing
- Undo and redo come for free, and tree invariants self-heal after every action, so the model never drifts into an invalid state.
- Controlled or not
- Run it uncontrolled and let dashfoo own the state, or drive the model yourself and persist it to localStorage or your backend.
- Primitives, hidden
- react-resizable-panels, @dnd-kit/dom, XState v5, and zod sit behind adapters. They stay bundled and hidden, so you never import them.
Up and running in one component
Install the engine and the React layer, give the mount a height, and resolve tab content with a registry or a factory. Tab content never lives in the model. That’s the whole setup.
Read the full guidepnpm add @dashfoo/core @dashfoo/reactimport { model, row, tabset, tab } from "@dashfoo/core";
import { DashfooLayout } from "@dashfoo/react";
const layout = model(
row([
tabset([tab("chart", "Chart"), tab("depth", "Depth")], { weight: 2 }),
tabset([tab("book", "Order Book")], { weight: 1 }),
]),
);
export const Dashboard = () => (
<DashfooLayout
defaultModel={layout}
factory={(t) => <Panel node={t} />}
/>
);Is dashfoo the right fit?
dashfoo is a split/tab tree, not a coordinate canvas. Popout windows, floating panels, and nested sub-layouts aren’t in v1.
Reach for dashfoo when…
- You need real docking: drag tabs to stack, split, or dock to an edge.
- You want to own every pixel of the chrome and style raw markup yourself.
- You want the layout as a serializable model you can save, diff, and restore.
- You want undo/redo and self-healing tree invariants for free.
Reach for something else when…
- You need a free 2D grid with absolute x/y/w/h. Reach for react-grid-layout.
- You want a turnkey, fully-styled panel UI out of the box.
- A simple two-pane resizable split is all you need. Use react-resizable-panels.
- You need panels that detach into native windows or float over the layout.
Build the dashboard your product needs
Install two packages, style the chrome yourself, and ship.