Sitelet https://docs.dashfoo.com/concepts
dashfoo

Concepts & terminology

The names dashfoo uses for tabs, panes, rows, splitters, and floating panels, with one annotated figure, the vocabulary, and the same layout as data.

dashfoo describes every layout with a small, fixed vocabulary. The same words appear in the model's node types, in the data-dashfoo="…" attributes you style, and in the reducer's action names. This page introduces them once, in one picture, before the deeper guides.

Anatomy of a layout

  1. 1Tab: one document: a component registry key plus a name label (TabNode). Tabs are the leaves of the tree.
  2. 2Tab strip: the row of tab buttons on a tabset; renderer chrome (data-dashfoo="tabstrip"), not a node.
  3. 3Tabset / pane: a tab strip plus one visible body; selected picks the visible tab (TabsetNode).
  4. 4Splitter / gutter: the draggable resize handle between the children of a row.
  5. 5Root row: the whole tiled area; orientation: "row" lays its children left-to-right (RowNode).
  6. 6Nested row: a row inside a row; orientation: "column" stacks its two tabsets top-to-bottom.
  7. 7Floating panel: a window-like panel above the grid with its own layout subtree and pixel geometry (FloatNode).
  8. 8Minimized chip: a floating panel collapsed to a pill docked at the layout edge (minimized: true).
The demo's overview layout, plus one floating panel and one minimized chip. The grey badges are node ids. The same ids appear in the model tree below.

Three of the labeled parts are node types in the model (RowNode, TabsetNode, TabNode), and floating panels are a fourth, FloatNode, which lives in Dashfoo.floats beside the tiled tree. The tab strip and the splitters are renderer chrome: they exist in the markup (data-dashfoo="tabstrip", data-dashfoo="splitter") but not in the model, which is why resizing a pane changes weight rather than storing pixel widths.

The vocabulary

TermIn the modelMeaning
TabTabNodeOne document: a component registry key plus a name label. Content never lives in the model. Your factory resolves the key at render.
Tab striprenderer chromeThe row of tab buttons on a tabset. global.tabLocation puts it at the "top" (default) or "bottom".
Tabset / paneTabsetNodeA tab strip plus one visible body; selected picks the visible tab.
Active tabsetactiveTabsetIdThe focused pane: the last one interacted with, tracked so chrome and themes can highlight it.
Maximized tabsetmaximizedTabsetIdOne tabset in the main layout rendered full-area, hiding its siblings until restored. Floats opt out of maximize.
RowRowNodeThe recursive container: lays children (tabsets or nested rows) along one axis.
Orientationorientation: "row" | "column"The row's axis: left-to-right or top-to-bottom.
WeightweightA child's share of its parent row's space, relative to its siblings.
Splitter / gutterrenderer chromeThe draggable resize handle between a row's children; global.splitterSize sets its thickness.
Dock location"center" | "split-left" | "split-right" | "split-top" | "split-bottom"Where a drop lands: stack into the tab strip, or split the pane toward an edge.
Floating panelFloatNodeA window-like panel above the grid with its own layout subtree and pixel geometry.
Minimized chipminimized: trueA floating panel collapsed to a small pill docked at the layout edge.

The floating panel is as close as dashfoo gets to a window. It renders in the same React tree, never in a separate browser window, so context, events, and styling stay connected. See Floating panels.

Row versus column

Rows are the only recursive container. The anatomy figure's right-hand column is a row with orientation: "column" nested inside the root row:

orientation: "row"

children flow left-to-right; the splitter is vertical

orientation: "column"

children stack top-to-bottom; the splitter is horizontal

The same two children under the two orientations. Nesting a column row inside a row (and vice versa) is how any grid of panes is built.

The same layout, as data

Everything above is one plain, serializable object: the Dashfoo model. Here is the anatomy figure again, as the tree the renderer reads. The ids match the grey badges in the figure:

  • Dashfooversion: 1 · activeTabsetId: "ts-main"
    • layout:rowrootorientation: "row"
      • tabsetts-mainweight: 2 · selected: 0
        • tabname: "Canvas" · component: "canvas"
        • tabname: "Detail" · component: "detail"
      • rowrightorientation: "column" · weight: 1
        • tabsetts-side-topweight: 1
          • tabname: "Activity"
          • tabname: "Tasks"
        • tabsetts-side-bottomweight: 1
          • tabname: "Metrics"
          • tabname: "History"
          • tabname: "Reports"
    • floats[0]:floatname: "Notes" · geometry: { left, top, width, height }
      • layout:roworientation: "row"
        • tabsetselected: 0
          • tabname: "Scratch"
One serializable object: the anatomy figure above, as data. The grey id badges match the figure; floats sit next to the tiled tree, each owning a layout subtree of the same shape.

The layout model walks this shape field by field, including the builders that write it tersely and the normalize() pass that keeps it canonical.

Where next

  • The layout model: the full node schema, builders, and self-healing invariants.
  • Drag and dock: how pointer position becomes a dock location.
  • Floating panels: floating, minimizing, and docking back.
  • Theming: styling the data-dashfoo="…" markup you saw above.