Bottom sheet
A panel that slides up from the bottom with a grab handle, and closes when you drag it down or tap outside.
Settings
Code
import { useState } from "react";
import { AnimatePresence, motion } from "framer-motion";
const spring = { type: "spring" as const, stiffness: 300, damping: 30 };
interface BottomSheetProps {
height?: number;
}
export default function BottomSheet({ height = 240 }: BottomSheetProps) {
const [open, setOpen] = useState(false);
return (
<div className="relative flex h-64 w-full flex-col items-center justify-center overflow-hidden rounded-2xl bg-black/5 text-[#1d1d1f] dark:text-[#f5f5f7] dark:bg-white/10 sm:h-72">
{/* Relleno: da a la caja 320 px de ancho natural sin impedir que encoja en pantallas estrechas */}
<svg aria-hidden className="h-0 w-80 max-w-full" />
<button
type="button"
onClick={() => setOpen(true)}
className="rounded-full bg-[#0071e3] px-5 py-2.5 text-sm font-medium text-white"
>
Open sheet
</button>
<AnimatePresence>
{open && (
<>
<motion.button
type="button"
aria-label="Close"
className="absolute inset-0 bg-[#1d1d1f]/10 dark:bg-[#f5f5f7]/10"
onClick={() => setOpen(false)}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
/>
<motion.div
drag="y"
dragConstraints={{ top: 0, bottom: 100 }}
onDragEnd={(_, info) => {
if (info.offset.y > 60) setOpen(false);
}}
initial={{ y: "100%" }}
animate={{ y: 0 }}
exit={{ y: "100%" }}
transition={spring}
className="absolute inset-x-0 bottom-0 rounded-t-[28px] bg-white dark:bg-[#1c1c1e] p-5 shadow-[0_4px_12px_rgba(0,0,0,0.04),0_24px_60px_rgba(0,0,0,0.1)]"
style={{ minHeight: `min(${height}px, 100%)` }}
>
<div className="mx-auto mb-5 h-1.5 w-10 rounded-full bg-black/5 dark:bg-white/10" />
<h3 className="text-lg font-semibold">Your next getaway</h3>
<p className="mt-1 text-sm text-[#86868b]">Save this stay for later.</p>
<button
type="button"
className="mt-5 w-full rounded-full bg-[#0071e3] py-3 text-sm font-medium text-white"
>
Save
</button>
</motion.div>
</>
)}
</AnimatePresence>
</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
On phones, a bottom sheet is kinder than a centered modal: it opens where the thumb already is and can be flicked away. Use it for “Save this place” on a travel app, picking a size in a shop or sharing a blog post. This React bottom sheet with drag to close behaves the way people expect from native apps.
Keep the content short enough to fit without scrolling inside the sheet; if it needs a long form, open a full page instead. Set the height so the page behind stays partly visible, which reminds people they can go back.