Dynamic island
FreeA compact pill that grows to show one live activity, then collapses.
pnpm dlx shadcn@latest add https://caliperui.site/r/dynamic-island.jsonWorkspace ready
When to use #
Use it for
- Ongoing work like exports and playback.
- One activity at a time.
Skip it when
- Several simultaneous activities; use a list.
Installation #
terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/dynamic-island.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
example.tsx
import { Upload } from "lucide-react" import { useState } from "react" import { Button } from "@/components/ui/button" import { DynamicIsland } from "@/components/ui/dynamic-island" export function ExportIsland() { const [view, setView] = useState<string | null>(null); return ( <div className="grid justify-items-center gap-4"> <div className="flex min-h-28 items-start justify-center"> <DynamicIsland label="Export activity" view={view} compact={<div className="flex items-center gap-2 text-xs"><span className="size-1.5 rounded-full bg-current" />Workspace ready</div>} > <div className="flex w-64 max-w-full items-center gap-3"> <Upload size={18} aria-hidden="true" /> <div> <p className="text-sm font-medium">Exporting review notes</p> <p className="mt-1 text-xs opacity-70">24% · local preview</p> </div> </div> </DynamicIsland> </div> <div className="flex gap-2"> <Button size="sm" variant="secondary" onClick={() => setView("export")}>Show export</Button> <Button size="sm" variant="ghost" onClick={() => setView(null)}>Collapse</Button> </div> </div> ); }
API reference #
DynamicIsland
component
PropTypeDefault
label *string—
view *string | null—
compact *ReactNode—
children *ReactNode—
classNamestring—
Accessibility #
It is built on native elements and keeps aria-label in step with state.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.