React + MotionOverlays

Dynamic Island toast

A small black pill at the top of the screen that stretches into a full notification when tapped.

Settings

300px

Code

import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
import { Bell, Check } from "lucide-react";

const spring = { type: "spring" as const, stiffness: 300, damping: 30 };

interface DynamicIslandToastProps {
  width?: number;
}

export default function DynamicIslandToast({ width = 300 }: DynamicIslandToastProps) {
  const [open, setOpen] = useState(false);

  return (
    <div className="relative h-40 w-full">
      <motion.button
        type="button"
        aria-expanded={open}
        onClick={() => setOpen((o) => !o)}
        animate={{
          width: open ? width : 130,
          height: open ? 82 : 38,
          borderRadius: open ? 24 : 22,
        }}
        transition={spring}
        className="absolute left-1/2 top-0 -translate-x-1/2 overflow-hidden bg-[#1d1d1f] text-[#f5f5f7] shadow-[0_4px_12px_rgba(0,0,0,0.04),0_24px_60px_rgba(0,0,0,0.1)]"
      >
        <AnimatePresence mode="wait">
          {open ? (
            <motion.span
              key="open"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              className="flex items-center gap-3 px-5 text-left"
            >
              <span className="grid h-10 w-10 place-items-center rounded-full bg-[#34c759]">
                <Check className="h-5 w-5" />
              </span>
              <span>
                <b className="block text-sm">Booking confirmed</b>
                <small className="text-[#f5f5f7]/60">You’re all set</small>
              </span>
            </motion.span>
          ) : (
            <motion.span
              key="closed"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              className="flex items-center justify-center gap-2 text-xs"
            >
              <Bell className="h-3.5 w-3.5" /> New alert
            </motion.span>
          )}
        </AnimatePresence>
      </motion.button>
    </div>
  );
}

Prompt for AI

Paste it into ChatGPT, Claude or Cursor and it will adapt the block to your project with these settings, even if you don’t use React.

More in Overlays

Where to use it

Inspired by the iPhone’s Dynamic Island, this toast starts as a discreet “New alert” pill and opens into a card with an icon, a title and a line of detail. It suits booking confirmations, order updates in a food delivery app or “Payment received” in an invoicing tool. As notifications go, the Dynamic Island style feels current without shouting.

In the demo it opens on click; in your app you will probably open it automatically after an action and close it after a few seconds. Set the open width so your longest message fits on one line.