Documentation
API: primitives (@fragiola/dockable-react)

Dockable.Panel

A tab's content panel, positioned by the engine over its tabset's content area and kept mounted when the tab moves.

"A tab's content panel (role="tabpanel"). Renders two portals:

  • the panel element, into the panel layer of the tab's current layout; the engine positions it over the tabset's content area and shows or hides it (structural style only);
  • the content (children), into the tab's moveable element, which the engine moves into whichever panel element is current.

The content's position in the React tree never changes (it always lives under Dockable.Panels), so moving a tab to another tabset or another window re-parents DOM without remounting the content."

<Dockable.Panels<Types>>
    {(tab) => (
        <Dockable.Panel
            node={tab}
            scrollable={tab.component !== "chart"}
            remountInWindow={tab.component === "video"}
            className="bg-palette-base text-palette-contrast"
        >
            <TabContent tab={tab} />
        </Dockable.Panel>
    )}
</Dockable.Panels>

Props

PanelProps<T> extends the common primitive props.

proptypedefaultdescription
nodeTabOf<T>requiredthe tab whose content this is
childrenReactNodenonethe tab's content
scrollablebooleantruethe content element scrolls its overflow; false clips it
remountInWindowbooleanfalseremount the content when the tab moves to another window (default: the same content moves, keeping its state). For content bound to its document (an iframe, a canvas context)

Both are view options, not model attributes: decide them per tab from tab.component or tab.data.

style (a value or a function) is accepted, but the keys the engine owns are dropped from it, and from the style of a render element: position, inset, left, top, right, bottom, width, height, display.

State

PanelState:

fieldtypedescription
selectedbooleanthe tab is its tabset's selected tab (model.is("tab-selected", { tabId }))
visiblebooleanthe panel is shown (selected, and not hidden by another tabset being maximized): engine.is("tab-panel-visible", { tabId: tab.id })

Data attributes and ARIA

attributevalue
data-layout-paththe tab's panel path: /ts0/t1
data-selectedthe selected tab
data-visibleshown
idengine.get("tab-panel-dom-id-by", { tabId: tab.id }), unique on the page (getTabPanelId(id, scope): dockable-<scope>tab-<id>)
role"tabpanel"
aria-labelledbyits tab button's id
aria-keyshortcutsthe focusTabToggle binding, when set
tabIndex-1 (focusable from code: Enter on the selected tab moves focus here)

Inside it, the content sits in the moveable element: <div data-dockable-moveable>, sized 100% by 100%, with overflow: auto (or hidden when scrollable is false).

Structural style

position: absolute from the first render. The engine writes left, top, width, height and display directly.

Behaviour

  • A press inside makes its tabset active (tabset.activate, through the model's middleware).
  • With focusTabToggle bound, that key (anywhere in the content) returns focus to the tab button.
  • remountInWindow remounts its content when the tab moves between windows (the content is keyed by its layout).

Styling notes

The panel is not a child of its tabset: the tabset's border-radius and overflow do not clip it, and tabset state selectors do not reach it (gap 2). It paints over absolutely positioned siblings that come before it in the root, so give overlays (the drop indicator) a z-index (gap 12).