Dock
beui/dockFreeComponent
macOS-style dock with grouped actions and a gliding active pill.
Install it
npx shadcn@latest add https://beui.dev/r/dock.jsonSource
1"use client";2// beui.dev/components/motion/dock34import { motion, useReducedMotion } from "motion/react";5import { createContext, useContext, useId, useMemo, type ReactNode } from "react";6import { SPRING_LAYOUT } from "@/lib/ease";7import { cn } from "@/lib/utils";89type DockContextValue = {10 size: number;11 pillLayoutId: string;12};1314const DockContext = createContext<DockContextValue | null>(null);1516export interface DockProps {17 children: ReactNode;18 className?: string;19 /** Size of each item in px. */20 size?: number;21}2223export function Dock({ children, size = 44, className }: DockProps) {24 const pillLayoutId = useId();25 const ctx = useMemo<DockContextValue>(26 () => ({ size, pillLayoutId }),27 [size, pillLayoutId],28 );2930 return (31 <DockContext.Provider value={ctx}>32 <div33 className={cn(34 "inline-flex h-auto items-end gap-1.5 rounded-2xl border border-border bg-card/80 px-2 py-1 shadow-2xl backdrop-blur-xl",35 className,36 )}37 >38 {children}39 </div>40 </DockContext.Provider>41 );42}4344export interface DockItemProps {45 children: ReactNode;46 className?: string;47 /** When set, the item renders as a <button>. Omit when children carry their own link or button. */48 onClick?: () => void;49 active?: boolean;50 "aria-label"?: string;51}5253export function DockItem({54 children,55 className,56 onClick,57 active,58 ...rest59}: DockItemProps) {60 const dock = useContext(DockContext);61 const reduce = useReducedMotion();62 const size = dock?.size ?? 44;63 const pillLayoutId = dock?.pillLayoutId ?? "dock-pill";6465 const pill = active ? (66 <motion.span67 layoutId={pillLayoutId}68 transition={reduce ? { duration: 0 } : SPRING_LAYOUT}69 className="absolute inset-0.5 -z-10 rounded-xl bg-primary/5"70 />71 ) : null;72 const sharedStyle = { width: size, height: size };73 const sharedClass = cn(74 "relative flex shrink-0 items-center justify-center rounded-full text-foreground",75 className,76 );7778 if (onClick) {79 return (80 <button81 type="button"82 onClick={onClick}83 aria-label={rest["aria-label"]}84 aria-pressed={active}85 style={sharedStyle}86 className={cn(87 sharedClass,88 "cursor-pointer border-0 bg-transparent p-0 outline-none",89 "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",90 )}91 >92 {pill}93 {children}94 </button>95// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Action Swap Bluraction-swap-blur | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Cascadeaction-swap-cascade | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Rollaction-swap-roll | beui | Components | Free | 3 deps · 4 files | |
| Agent Activityagent-activity | beui | Components | Free | 4 deps · 9 files | |
| Agent Loading States Agent Progressagent-progress | beui | Components | Free | 3 deps · 3 files | |
| AI Sidebarai-sidebar | beui | Components | Free | 4 deps · 5 files | |
| Animated Badgeanimated-badge | beui | Components | Free | 4 deps · 3 files | |
| Number Animation Animated Numberanimated-number | beui | Components | Free | 3 deps · 3 files |
