A floating status pill for live activities — idle, now playing, timer, incoming call and upload — whose dark shell springs between sizes while content crossfades through a blur.
dynamic islandioslive activitymusictimercalluploadmorphnotification
Installation
Pro installs use your private registry token. Add the @geturui-pro registry once — setup guide. The command works after you get Pro.
$npx shadcn@latest add @geturui-pro/dynamic-island
Usage
usage.tsx
1"use client";
2import * as React from "react";
3import { DynamicIsland, type IslandView } from "@/components/ui/dynamic-island";
4
5export function NowPlaying() {
6 const [view, setView] = React.useState<IslandView>("music");
7 const [playing, setPlaying] = React.useState(true);
8 return (
9 <DynamicIsland
10 view={view}
11 music={{ title: "Spring Physics", artist: "Damping Ratio", playing }}
12 timer={{ seconds: 120, label: "Tea timer" }}
13 call={{ name: "Maya Chen", initials: "MC" }}
14 upload={{ name: "release-notes.pdf", progress: 64 }}
15 onTogglePlay={() => setPlaying((p) => !p)}
16 onAcceptCall={() => setView("idle")}
17 onDeclineCall={() => setView("idle")}
18 onTimerEnd={() => setView("idle")}
19 />
20 );
21}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
view* | "idle" | "music" | "timer" | "call" | "upload" | — | Which live activity to show. Changing it morphs the shell. |
music | { title: string; artist: string; playing?: boolean; coverInitials?: string } | — | Now-playing data. Waveform bars bounce while playing is true. |
timer | { seconds: number; label?: string } | — | Countdown that starts each time the timer view appears. |
call | { name: string; subtitle?: string; initials?: string } | — | Incoming caller shown with accept and decline buttons. |
upload | { name: string; progress: number } | — | File name and 0–100 progress drawn as a ring. |
expanded | boolean | — | Music view only: show the full player. Uncontrolled (tap to toggle) when omitted. |
onExpandedChange | (expanded: boolean) => void | — | Called when the player expands or collapses. |
onTogglePlay | () => void | — | Play / pause pressed in the expanded player. |
onSkip | (direction: -1 | 1) => void | — | Previous or next track pressed. |
onAcceptCall | () => void | — | Accept pressed in the call view. |
onDeclineCall | () => void | — | Decline pressed in the call view. |
onTimerEnd | () => void | — | Fired when the countdown reaches zero. |
className | string | — | Classes for the outer wrapper. |
Accessibility
- The island is a labelled region with a polite live region that announces activity changes (not every timer tick).
- Every control is a real button with a descriptive label, e.g. "Accept call from Maya Chen"; the compact player is a button with aria-expanded.
- With reduced motion the shell resizes with a short tween, content fades without blur and the waveform and ringing wiggle stop.
- The shell is always black, like the hardware cutout it imitates; text and accents keep contrast in both themes.