Dockable
Guides

Menus

The package provides the actions and the label keys; you render the menu with your own components.

Dockable renders no menus. A tab context menu, a tabset "more" menu or an overflow menu is a component you write, whose items dispatch actions. This page lists the items a layout usually offers and the action behind each.

Intermediate exampleTab context menuA Fragiola ContextMenu on every tab: close, close others, close to the right, rename, pin, maximize and pop out. Unavailable items are disabled from the model's own flags.Open the live example

A tab context menu

Attach the menu to the Tab with onContextMenu (props are forwarded), or wrap the tab in your menu library's trigger with render. With Fragiola UI's ContextMenu (Base UI):

import { Actions, type TabNode } from "@fragiola/dockable";
import { Dockable, useDockable } from "@fragiola/dockable-react";
import { ContextMenu } from "@/components/ui/context-menu";

function TabWithMenu({ tab }: { tab: TabNode }) {
    const { engine } = useDockable();
    return (
        <ContextMenu.Root>
            <ContextMenu.Trigger render={<Dockable.Tab node={tab} />}>
                {tab.getName()}
            </ContextMenu.Trigger>
            <ContextMenu.Content>
                <ContextMenu.Item
                    disabled={!tab.isCloseable()}
                    onClick={() => engine.doAction(Actions.deleteTab(tab.getId()))}
                >
                    Close
                </ContextMenu.Item>
                <ContextMenu.Item onClick={() => engine.doAction(Actions.setTabPinned(tab.getId(), !tab.isPinned()))}>
                    {tab.isPinned() ? "Unpin" : "Pin"}
                </ContextMenu.Item>
            </ContextMenu.Content>
        </ContextMenu.Root>
    );
}

Read the component's source for its exact parts; the pattern (a trigger rendering the Dockable.Tab, items dispatching actions) is the same with any menu library. Make sure the trigger forwards the ref and props to the tab element, or wrap the tab in the trigger instead.

The usual items

itemactionshow or enable whenlabel key
CloseActions.deleteTab(tab.getId())tab.isCloseable()Close_Tab
Close othersActions.group(others.map((t) => Actions.deleteTab(t.getId())))other closeable tabs existMenu_Close_Others
Close to the rightActions.group(right.map(…))closeable tabs after itMenu_Close_Right
Close allActions.group(all.map(…))closeable tabs existMenu_Close_All
Renamestart your rename UI, then Actions.renameTab(id, text)tab.isEnableRename()Menu_Rename
Pin / UnpinActions.setTabPinned(id, !tab.isPinned())tab.isEnablePin()Menu_Pin, Menu_Unpin
Pop outActions.popoutTab(id, "window")tab.isEnablePopout() and mainEngine.isSupportsPopout()Menu_Popout
Maximize / RestoreActions.maximizeToggle(tabset.getId())tabset.isEnableMaximize()Menu_Maximize, Menu_Restore

Group the "close several" items with Actions.group, so they are one undo step and one onModelChange. Filter with isCloseable(): pinned tabs are not closeable.

The label keys are members of DockableLabel. They have no text in the package; resolving them through the same getLabel you give Dockable.Root keeps every string of the layout in one map (see Accessible names).

A context menu opened on a tab does not interfere with dragging (a drag starts from a primary button press and a move). Keep menu triggers from starting a drag of their own: a menu button inside a tab should stop pointerdown propagation, as the close button does in Tabs.

Overflow menus

A menu listing a tabset's hidden tabs is covered in Tab overflow.

On this page