Dock
The Liquid Glass shelf of app icons with magnification, running indicators, badges, labels and auto-hide. Windows minimize into it.
"use client"
import type * as React from "react"
import {
CalendarIcon,
CompassIcon,
FolderIcon,
MailIcon,
MessageCircleIcon,
MusicIcon,
SettingsIcon,
Trash2Icon,
} from "lucide-react"
import { Dock, DockIcon, DockItem, DockSeparator } from "@/components/ui/dock"
const apps: {
name: string
icon: React.ComponentType
className: string
running?: boolean
badge?: number
}[] = [
{ name: "Finder", icon: FolderIcon, className: "bg-linear-to-b from-sky-400 to-blue-600 text-white", running: true },
{ name: "Safari", icon: CompassIcon, className: "bg-linear-to-b from-white to-zinc-200 text-blue-500", running: true },
{ name: "Messages", icon: MessageCircleIcon, className: "bg-linear-to-b from-lime-400 to-green-600 text-white", badge: 3 },
{ name: "Mail", icon: MailIcon, className: "bg-linear-to-b from-sky-300 to-blue-500 text-white", running: true, badge: 156 },
{ name: "Music", icon: MusicIcon, className: "bg-linear-to-b from-rose-400 to-red-600 text-white" },
{ name: "Calendar", icon: CalendarIcon, className: "bg-white text-red-500" },
{ name: "System Settings", icon: SettingsIcon, className: "bg-linear-to-b from-zinc-300 to-zinc-500 text-zinc-800" },
]
export default function DockDemo() {
return (
<div className="flex h-40 items-end">
<Dock size={56} magnification={84}>
{apps.map((app) => (
<DockItem key={app.name} label={app.name} running={app.running} badge={app.badge}>
<DockIcon className={app.className}>
<app.icon />
</DockIcon>
</DockItem>
))}
<DockSeparator />
<DockItem label="Trash">
<DockIcon className="bg-white/25 text-white">
<Trash2Icon />
</DockIcon>
</DockItem>
</Dock>
</div>
)
}Installation
pnpm dlx shadcn@latest add @cupertinoui/dockThe first install also adds the macOS theme. See Installation to set up the registry.
Usage
import { Dock, DockIcon, DockItem, DockSeparator } from "@/components/ui/dock"
<Dock magnification={77}>
<DockItem label="Finder" running>
<DockIcon className="bg-blue-500 text-white">
<FolderIcon />
</DockIcon>
</DockItem>
<DockItem label="Mail" running badge={3}>
<DockIcon className="bg-blue-500 text-white">
<FolderIcon />
</DockIcon>
</DockItem>
<DockSeparator />
<DockItem label="Trash">
<Trash2Icon />
</DockItem>
</Dock>Examples
Auto-hide
With autoHide, the Dock stays out of the way until the pointer reaches the bottom edge of its container. Set revealed to show it from code, e.g. while a window minimizes into it.
"use client"
import { CompassIcon, FolderIcon, MailIcon, MusicIcon } from "lucide-react"
import { Dock, DockIcon, DockItem } from "@/components/ui/dock"
const apps = [
{ name: "Finder", icon: FolderIcon, className: "bg-linear-to-b from-sky-400 to-blue-600 text-white" },
{ name: "Safari", icon: CompassIcon, className: "bg-linear-to-b from-white to-zinc-200 text-blue-500" },
{ name: "Mail", icon: MailIcon, className: "bg-linear-to-b from-sky-300 to-blue-500 text-white" },
{ name: "Music", icon: MusicIcon, className: "bg-linear-to-b from-rose-400 to-red-600 text-white" },
]
// The Dock slides in when the pointer reaches the bottom edge of its
// container, and slides away again when the pointer moves up.
export default function DockAutoHide() {
return (
<div className="relative flex h-48 w-full max-w-lg items-center justify-center overflow-hidden rounded-mac-group border border-dashed border-white/30 px-6 text-center text-mac-body text-white/80">
Move the pointer to the bottom edge of this area.
<Dock autoHide size={40} className="absolute bottom-2 left-1/2 -translate-x-1/2">
{apps.map((app) => (
<DockItem key={app.name} label={app.name}>
<DockIcon className={app.className}>
<app.icon />
</DockIcon>
</DockItem>
))}
</Dock>
</div>
)
}Minimizing windows
Pass a ref to a DockItem as a Window's minimizeTo, and the window minimizes into it with the Genie effect.
"use client"
import * as React from "react"
import { FileTextIcon } from "lucide-react"
import { Dock, DockIcon, DockItem } from "@/components/ui/dock"
import {
Window,
WindowContent,
WindowControls,
WindowMain,
WindowTitle,
WindowTitlebar,
} from "@/components/ui/window"
// The yellow traffic light minimizes the window into its app's Dock icon
// with the Genie effect; click the icon to bring it back. The green one
// zooms it to fill the area, the red one closes it.
export default function WindowMinimize() {
const [open, setOpen] = React.useState(true)
const [minimized, setMinimized] = React.useState(false)
const [maximized, setMaximized] = React.useState(false)
const icon = React.useRef<HTMLButtonElement>(null)
return (
<div className="relative h-96 w-full max-w-2xl overflow-hidden">
{open && (
<Window
className="absolute inset-x-0 top-6 mx-auto h-56 w-80"
minimized={minimized}
minimizeTo={icon}
maximized={maximized}
maximizeInsets={{ top: 8, right: 8, bottom: 88, left: 8 }}
onClose={() => {
setOpen(false)
setMaximized(false)
}}
onMinimize={() => setMinimized(true)}
onZoom={() => setMaximized((value) => !value)}
>
<WindowMain>
<WindowTitlebar>
<WindowControls />
<WindowTitle>Notes.txt</WindowTitle>
</WindowTitlebar>
<WindowContent className="p-4 text-mac-label-secondary">
Minimize me into the Dock, or double-click the title bar to zoom.
</WindowContent>
</WindowMain>
</Window>
)}
<Dock size={48} className="absolute bottom-2 left-1/2 -translate-x-1/2">
<DockItem
ref={icon}
label="TextEdit"
running={open}
onClick={() => {
setOpen(true)
setMinimized(false)
}}
>
<DockIcon className="bg-linear-to-b from-white to-zinc-200 text-zinc-600">
<FileTextIcon />
</DockIcon>
</DockItem>
</Dock>
</div>
)
}API Reference
Every part forwards the props of the underlying Base UI Tooltip part. The props below are the ones CupertinoUI adds or changes.
Dock
| Prop | Type | Description |
|---|---|---|
size | numberDefault: 51 | The tile size in pixels, like the Size slider in Desktop & Dock settings. Tiles sit 2px apart. |
magnification | number | The size a tile grows to under the pointer. Tiles up to four places away grow less. Leave it out to turn magnification off. |
autoHide | booleanDefault: false | Hides the Dock until the pointer reaches the bottom edge of its container. |
revealed | booleanDefault: false | Shows an auto-hiding Dock regardless of the pointer. |
className | string | Extra classes, merged with the component's own. |
DockItem
A button laid over the item's content, so the content can be anything, even a live miniature of a window. Takes the props of a button; its ref is the button.
| Prop | Type | Description |
|---|---|---|
label | ReactNode | Shown in a tooltip above the item, and used as its accessible name when it is a string. |
running | booleanDefault: false | Shows the dot below the icon. |
badge | ReactNode | A red badge in the top-right corner, e.g. an unread count. |
className | string | Extra classes, merged with the component's own. |
DockIcon
A squircle app icon on the icon grid. Give it a background and put a symbol inside.
| Prop | Type | Description |
|---|---|---|
className | string | Extra classes, merged with the component's own. |
DockSeparator
The divider between apps and minimized windows, folders or the Trash.
| Prop | Type | Description |
|---|---|---|
className | string | Extra classes, merged with the component's own. |