Skip to main content

Tree structure

Every layout in react-mosaic is a MosaicNode<T> — a tree of three kinds of node:

  1. Leaf nodes — a single panel, represented by its key of type T.
  2. Split nodes{ type: 'split', direction, children, splitPercentages? }. Holds any number of child nodes laid out horizontally ('row') or vertically ('column').
  3. Tab nodes{ type: 'tabs', tabs, activeTabIndex }. Holds any number of leaf keys and displays them as a tab group.

The type signature is:

type MosaicNode<T extends MosaicKey> =
| MosaicSplitNode<T>
| MosaicTabsNode<T>
| T;

interface MosaicSplitNode<T> {
type: 'split';
direction: 'row' | 'column';
children: MosaicNode<T>[];
/** Array summing to 100. Omit for equal distribution. */
splitPercentages?: number[];
}

interface MosaicTabsNode<T> {
type: 'tabs';
tabs: T[];
activeTabIndex: number;
}

Try it

The code block below is live — edit any value and the preview above it updates immediately. Change direction, add a third child to children, adjust splitPercentages:

Live Editor
function TreeStructureExample() {
  return (
    <div className="live-mosaic-frame">
      <Mosaic
        renderTile={(id, path) => (
          <MosaicWindow path={path} title={`Panel ${id}`}>
            <div style={{ padding: 20, fontFamily: 'sans-serif' }}>
              <strong>{id}</strong>
            </div>
          </MosaicWindow>
        )}
        initialValue={{
          type: 'split',
          direction: 'row',
          splitPercentages: [30, 40, 30],
          children: [
            'left',
            {
              type: 'tabs',
              tabs: ['inbox', 'drafts', 'sent'],
              activeTabIndex: 0,
            },
            {
              type: 'split',
              direction: 'column',
              splitPercentages: [60, 40],
              children: ['main', 'console'],
            },
          ],
        }}
      />
    </div>
  );
}
Result
Loading...

Paths

A MosaicPath is the route to a node through the tree, expressed as an array of numeric indices:

  • [] — the root
  • [0] — first child of the root
  • [1, 2] — third child of the second child of the root

Paths are how every tree-manipulation utility identifies which node to operate on. The path argument you receive in renderTile and MosaicWindow is the path to that panel's current location — you don't track it yourself, the component gives it to you.

Leaf keys

Panel identifiers (T) must be serialisable and unique within the tree. string and number are both fine. The library does not care what the key means — it's your identifier for whatever that panel represents (a file, a report, a view mode, a tab inside your own model).

Leaf keys appear:

  • In the tree as bare values (children: ['a', 'b']).
  • As the first argument to your renderTile function.
  • As the first argument to TabTitleRenderer, TabButtonRenderer, etc.

Why n-ary?

Before v7, split nodes were binary: every split had first and second children. Adding a third panel meant nesting another split inside, which made the tree deep and the indices shift every time you added a panel.

N-ary splits let a single split hold three, five, ten children with one splitPercentages array. The "auto arrange" action in the demo demonstrates the difference directly — notice the tree stays shallow.

If you have a legacy binary tree in storage, you don't need to migrate it manually: <Mosaic value={legacyTree}> converts on the fly, and convertLegacyToNary is available for explicit upgrades.