Skip to content

DockShell ​

The floating bar at the bottom of a canvas-like view, and the one place that knows how to get out of the way.

tsx
import { DockShell } from '@basmilius/react-ui';
tsx
import { useState } from 'react';
import { Hand, MousePointer2, Square, Type } from 'lucide-react';
import { ButtonGroup, DockShell, IconButton, Separator, Switch } from '@basmilius/react-ui';

const TOOLS = [
    { id: 'select', label: 'Select', icon: MousePointer2 },
    { id: 'pan', label: 'Pan', icon: Hand },
    { id: 'box', label: 'Box', icon: Square },
    { id: 'text', label: 'Text', icon: Type }
];

export default function DockShellDemo() {
    const [tool, setTool] = useState('select');
    const [autoHide, setAutoHide] = useState(false);

    return (
        <div className="relative h-72 w-full overflow-hidden rounded-lg bg-surface-sunken">
            <label className="absolute top-3 left-3 flex items-center gap-2 text-xs text-text-muted">
                <Switch label="Hide the dock" checked={autoHide} onCheckedChange={setAutoHide} />
                Hide until the pointer comes down
            </label>
            <DockShell autoHide={autoHide}>
                <ButtonGroup>
                    {TOOLS.map((entry) => (
                        <IconButton key={entry.id} icon={entry.icon} label={entry.label} active={tool === entry.id} onClick={() => setTool(entry.id)} />
                    ))}
                </ButtonGroup>
                <Separator />
                <span className="px-2 text-xs text-text-muted">{TOOLS.find((entry) => entry.id === tool)?.label}</span>
            </DockShell>
        </div>
    );
}

With autoHide the dock waits below the edge until the pointer comes within 120 pixels of the bottom of the window. An open menu in the dock keeps it up, since the menu's popup would slide away with it. A keyboard reaches it by tabbing. The buttons stay in the tab order while the dock is out of sight, and focus inside it brings it back.

Something that moves with the dock, such as a popover standing on it, marks itself with data-holds-dock, so reaching for it does not hide the dock under the pointer. onHiddenChange tells you whenever the bar slides away or comes back, for anything that stands on top of it.

The dock is absolutely positioned at the bottom center of its positioned parent, and the bar is a Surface.

Props ​

DockShell renders a <div> and takes its props, plus:

PropTypeDefault
childrenReactNodeRequired.
autoHidebooleanfalse
barClassNamestringClasses for the bar itself, such as letting a dock with many buttons wrap.
onHiddenChange(hidden: boolean) => void

DockShellProps is an exported type.