Skip to main content
NachUI

Dock

A floating bar of icon actions with tooltips, magnification and auto hide.

1'use client';
2
3import { useState } from 'react';
4import { Dock } from '@/components/ui/dock';
5import { BookIcon } from '@/components/ui/book';
6import { HomeIcon } from '@/components/ui/home';
7import { LayoutGridIcon } from '@/components/ui/layout-grid';
8import { MoonIcon } from '@/components/ui/moon';
9import { SearchIcon } from '@/components/ui/search';
10import { SparklesIcon } from '@/components/ui/sparkles';
11
12const ITEMS = [
13 { id: 'home', label: 'Home', icon: HomeIcon },
14 { id: 'docs', label: 'Docs', icon: BookIcon },
15 { id: 'components', label: 'Components', icon: LayoutGridIcon },
16];
17
18export function Default() {
19 const [active, setActive] = useState('home');
20
21 return (
22 <Dock floating={false} label="Demo dock">
23 {ITEMS.map(({ id, label, icon: Icon }) => (
24 <Dock.Item key={id} label={label} active={active === id} onClick={() => setActive(id)}>
25 <Icon />
26 </Dock.Item>
27 ))}
28 <Dock.Separator />
29 <Dock.Item label="Search">
30 <SearchIcon />
31 </Dock.Item>
32 <Dock.Item label="Ask AI">
33 <SparklesIcon />
34 </Dock.Item>
35 <Dock.Item label="Toggle theme">
36 <MoonIcon />
37 </Dock.Item>
38 </Dock>
39 );
40}

Installation

pnpm dlx nachui add dock

Anatomy

1import { Dock, useDockAutoHide } from '@/components/ui/dock';
1<Dock label="Site navigation">
2 <Dock.Item label="Home" active>
3 <HomeIcon />
4 </Dock.Item>
5 <Dock.Separator />
6 <Dock.Item label="Search">
7 <SearchIcon />
8 </Dock.Item>
9</Dock>
Every item takes a label. It is the accessible name of the control and the tooltip that appears on hover or focus, so the icon alone never has to explain itself.
Pass asChild to turn the item into whatever you render inside it, like a router link. The item keeps its size, tooltip and active state.
1'use client';
2
3import { Dock } from '@/components/ui/dock';
4import { BookIcon } from '@/components/ui/book';
5import { HomeIcon } from '@/components/ui/home';
6import { PackageIcon } from '@/components/ui/package';
7import { StarIcon } from '@/components/ui/star';
8
9export function Links() {
10 return (
11 <Dock floating={false} label="Site navigation">
12 <Dock.Item asChild label="Home">
13 <a href="#home">
14 <HomeIcon />
15 </a>
16 </Dock.Item>
17 <Dock.Item asChild label="Docs" active>
18 <a href="#docs">
19 <BookIcon />
20 </a>
21 </Dock.Item>
22 <Dock.Item asChild label="Bricks">
23 <a href="#bricks">
24 <PackageIcon />
25 </a>
26 </Dock.Item>
27 <Dock.Item asChild label="Icons">
28 <a href="#icons">
29 <StarIcon />
30 </a>
31 </Dock.Item>
32 </Dock>
33 );
34}

Magnification

Items grow as the pointer gets close, the way a desktop dock does. Tune it with itemSize, magnifiedSize and range, or turn it off with magnify={false}. It is off automatically when the visitor prefers reduced motion, and it never runs on touch.
1<Dock itemSize={44} magnifiedSize={68} range={140}>
2 ...
3</Dock>

Auto hide

useDockAutoHide returns true while the page scrolls down and false when it scrolls up, reaches the bottom, or the pointer comes near the bottom edge. Feed it to hidden and the bar slides out of the way.
1function SiteDock() {
2 const hidden = useDockAutoHide();
3
4 return (
5 <Dock hidden={hidden} label="Site navigation">
6 ...
7 </Dock>
8 );
9}
By default the bar is fixed to the bottom center of the viewport. Use floating={false} to render it in place, for example inside a toolbar or a demo.

API Reference

Dock

PropTypeDefaultDescription
labelstring'Dock'Accessible name of the navigation landmark.
hiddenbooleanfalseSlides the bar out and disables pointer events.
floatingbooleantrueFixes the bar to the bottom center of the viewport.
magnifybooleantrueGrow items near the pointer.
itemSizenumber40Resting size of each item in pixels.
magnifiedSizenumber60Size of the item right under the pointer.
rangenumber120Distance in pixels over which the magnification fades out.

Dock.Item

PropTypeDefaultDescription
labelstringAccessible name and tooltip text. Required.
activebooleanfalseMarks the current item with a dot and aria-current.
asChildbooleanfalseRender the child element instead of a button.
containerClassNamestringClasses for the outer box, useful to hide items per breakpoint.

Dock.Separator

A vertical rule between groups of items. Accepts the usual className.

useDockAutoHide

OptionTypeDefaultDescription
thresholdnumber12Minimum scroll delta before the state changes.
revealZonenumber96Pointer distance from the bottom edge that reveals.
minScrollnumber80Scroll position under which the bar never hides.
Found something to improve?

Notice a bug, typo, or missing detail on this page? Help us make the documentation better by opening a GitHub issue.

Create an Issue