Dockable.TabList
The tab strip of a tabset or border calls the child function per tab and moves focus between tabs with the arrow keys.
"The tabset's tab strip (role="tablist"). Calls the child function per tab. Arrow keys along
the orientation (Left and Right swap in RTL, where a horizontal strip runs from
the right), Home and End move focus between tabs; Enter or Space selects."
<Dockable.TabList<Types> aria-label={tabset.data?.name ?? "Tabs"} className="flex min-h-8 ps-1">
{(tab) => (
<Dockable.Tab node={tab} className="tab">
{tab.component === "editor" && tab.data.dirty ? `${tab.label} •` : tab.label}
</Dockable.Tab>
)}
</Dockable.TabList>The child function receives a plain TabOf<T>. Pass the model's registry as the type argument
(<Dockable.TabList<Types>>): the list reads its tabs from the enclosing TabSet or Border
through context, so it cannot infer T, and with the argument tab.data narrows on
tab.component. Without it, T is AnyTypes and tab.data is unknown.
Render it inside a Dockable.TabSet (or a Dockable.Border). The engine measures it: the strip's
rect is used for drop hit-testing, and the tabs that do not fit in it are hidden (tab overflow),
for a Dockable.TabOverflowTrigger to list.
Props
TabListProps<T> extends the common primitive props.
| prop | type | default | description |
|---|---|---|---|
children | (tab: TabOf<T>) => ReactNode | required | renders a tab button (a Dockable.Tab); pass the model's registry as the type argument (<Dockable.TabList<Types>>) and tab.data narrows on tab.component |
orientation | "horizontal" | "vertical" | "horizontal" ("vertical" in a start or end border) | the direction the tabs are laid out in, for arrow key navigation; default horizontal (vertical in a start or end border) |
overflow | boolean | true | tab overflow: the tabs that do not fit are hidden (the selected one stays), for a Dockable.TabOverflowTrigger to list; false keeps every tab, for a strip that wraps or scrolls |
State
TabListState:
| field | type | description |
|---|---|---|
orientation | "horizontal" | "vertical" | the orientation prop |
dropTarget | boolean | the current drag would drop into this tab strip |
dropIndex | number | undefined | while it is the drop target: the insertion index in the strip |
overflowing | boolean | some tabs do not fit, so they are hidden (list them with Dockable.TabOverflowTrigger) |
Data attributes and ARIA
| attribute | value |
|---|---|
data-layout-path | <tabset path>/tabstrip, e.g. /ts0/tabstrip |
data-orientation | "horizontal" or "vertical" |
data-drop-target | the current drag would drop into this tab strip |
data-drop-index | while it is the drop target: the insertion index among the tabset's children |
data-overflowing | some tabs do not fit, so they are hidden |
role | "tablist" |
aria-orientation | the orientation |
aria-keyshortcuts | the focusNextTabset/focusPreviousTabset bindings, when set |
Name it with aria-label (from the tabset's data, when the app keeps a name there).
Styling notes
- Keep it at least ~30px tall at the top of the layout, or lower the global
edgeDockMargin: the layout's top-edge docking band is 10px (gap 11). - No structural style: layout and wrapping are yours. Give the list a size the tabs can overflow
(
flex: 1; min-width: 0in a header row,overflow: hidden): tab overflow compares the tabs' sizes, plus the list'sgap, with the list's inner size (Tab overflow).
In a border
Dockable.TabList works the same inside Dockable.Border: its path is
/border/<location>/tabstrip, and it runs vertically in a start or end border. The border's strip
(Dockable.Border) is what the engine measures there, not the tab list.