Back to Dictionary
Status & Confirmation
●●○Customize
Context dependentDynamic Island Expand
A top-anchored capsule that fluidly morphs into a larger notification card, accommodating new UI controls, and smoothly reverts to a resting pill shape.
Use
System-level background tasks
Avoid
Complex forms
Safer Alternative
No safer default listed.
Risk Level
Low risk
Live Demo
System Active
What It Is
A top-anchored capsule that fluidly morphs into a larger notification card, accommodating new UI controls, and smoothly reverts to a resting pill shape.
✓When to Use
- System-level background tasks
- Music player mini-status
- Toast notification alternatives
✕When NOT to Use
- Complex forms
- Critical blocking alerts
Configuration Tips
- 01Use Framer Motion `layout` prop on the container to automatically interpolate width, height, and border-radius.
You've Seen It In
iOS 16+Vercel Deployment StatusPremium Web Dashboards
AI Implementation Prompts
Move from a fast scaffold to production details, then tune timing and edge states.
Create a black pill-shaped div that uses framer-motion layout to seamlessly expand into a larger rounded rectangle card when clicked.
Reference Implementation
The same implementation approach used by the live preview, kept compact enough to inspect and adapt.
"use client";
import { motion, AnimatePresence } from 'framer-motion';
import { useState, useEffect } from 'react';
export function DynamicIslandExpandDemo({ isPlaying = false }: { isPlaying?: boolean }) {
const [isExpanded, setIsExpanded] = useState(false);
useEffect(() => {
if (!isPlaying) {
setIsExpanded(false);
return;
}
const loop = setInterval(() => {
setIsExpanded(prev => !prev);
}, 2000);
return () => clearInterval(loop);
}, [isPlaying]);
return (
<div className="flex h-64 w-full items-start justify-center overflow-hidden rounded-2xl bg-stone-50 pt-8 shadow-sm ring-1 ring-stone-200 cursor-pointer" onClick={() => setIsExpanded(!isExpanded)}>
<motion.div
layout
initial={false}
animate={{
width: isExpanded ? 320 : 120,
height: isExpanded ? 160 : 36,
borderRadius: isExpanded ? 32 : 18
}}
transition={{ type: "spring", stiffness: 300, damping: 25 }}
className="bg-black origin-top flex flex-col overflow-hidden text-white"
>
{"text-stone-400 italic">/* Compact State (Always visible but shifts layout) */}
<motion.div layout className="flex w-full h-[36px] items-center justify-center shrink-0">
<AnimatePresence mode="popLayout">
{!isExpanded && (
<motion.div
key="compact-content"
initial={{ opacity: 0, filter: "blur(4px)" }}
animate={{ opacity: 1, filter: "blur(0px)" }}
exit={{ opacity: 0, filter: "blur(4px)", scale: 0.8 }}
className="flex items-center gap-2"
>
<div className="w-2.5 h-2.5 rounded-full bg-emerald-500 animate-pulse" />
<span className="text-xs font-medium">System Active</span>
</motion.div>
)}
</AnimatePresence>
</motion.div>
{"text-stone-400 italic">/* Expanded State Content */}
<AnimatePresence>
{isExpanded && (
<motion.div
key="expanded-content"
initial={{ opacity: 0, y: 10, filter: "blur(4px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
exit={{ opacity: 0, y: -10, filter: "blur(4px)" }}
transition={{ delay: 0.1 }}
className="flex flex-col px-6 pb-6 pt-2 h-full justify-between"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-indigo-500 flex items-center justify-center">
<svg className="w-5 h-5 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 10V3L4 14h7v7l9-11h-7z" />
</svg>
</div>
<div className="flex flex-col">
<span className="text-sm font-bold">Background Sync</span>
<span className="text-xs text-stone-400">Downloading updates...</span>
</div>
</div>
<div className="w-8 h-8 rounded-full bg-white/10 flex items-center justify-center">
<svg className="w-4 h-4 text-white" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</div>
</div>
<div className="mt-4 flex gap-2">
<div className="h-10 flex-1 rounded-xl bg-white/10 flex items-center justify-center text-xs font-bold text-stone-300">Pause</div>
<div className="h-10 flex-1 rounded-xl bg-white/10 flex items-center justify-center text-xs font-bold text-white">Details</div>
</div>
</motion.div>
)}
</AnimatePresence>
</motion.div>
</div>
);
}