Family Drawer
rare-ui/family-drawerFreeComponent
A bottom drawer with smooth, morphing transitions between stacked views, inspired by the Family app. Built on Vaul.
Install it
npx shadcn@latest add https://rareui.com/r/family-drawer.jsonSource
1"use client";23import { useMemo, useRef, useState, type ReactNode } from "react";45type SetView = (view: string) => void;6import { Drawer } from "vaul";7import useMeasure from "react-use-measure";8import { motion, AnimatePresence } from "motion/react";9import clsx from "clsx";101112export default function FamilyDrawer() {13 const [isOpen, setIsOpen] = useState(false);14 const [view, setView] = useState("default");15 const [elementRef, bounds] = useMeasure();16 const previousHeightRef = useRef<number | null>(null);1718 const content = useMemo(() => {19 switch (view) {20 case "default":21 return <DefaultView setView={setView} />;22 case "remove":23 return <RemoveWallet setView={setView} />;24 case "phrase":25 return <Phrase setView={setView} />;26 case "key":27 return <Key setView={setView} />;28 }29 }, [view]);3031 const opacityDuration = useMemo(() => {32 const MIN_DURATION = 0.15;33 const MAX_DURATION = 0.27;3435 if (!previousHeightRef.current) {36 previousHeightRef.current = bounds.height;37 return MIN_DURATION;38 }3940 const heightDifference = Math.abs(41 bounds.height - previousHeightRef.current,42 );43 previousHeightRef.current = bounds.height;4445 const duration = Math.min(46 Math.max(heightDifference / 500, MIN_DURATION),47 MAX_DURATION,48 );4950 return duration;51 }, [bounds.height]);5253 return (54 <>55 <button56 className="focus-visible:shadow-focus-ring-button absolute top-1/2 left-1/2 h-[44px] -translate-x-1/2 -translate-y-1/2 rounded-full border border-gray-200 bg-white px-4 py-2 font-medium text-black transition-colors hover:bg-[#F9F9F8] md:font-medium dark:border-none dark:bg-muted dark:shadow-sm dark:text-foreground dark:hover:bg-muted"57 onClick={() => setIsOpen(true)}58 style={{ fontFamily: "var(--font-open-runde)" }}59 >60 Try it out61 </button>62 <Drawer.Root open={isOpen} onOpenChange={setIsOpen}>63 <Drawer.Portal>64 <Drawer.Overlay65 className="fixed inset-0 z-[60] bg-black/30 backdrop-blur-xs"66 onClick={() => setIsOpen(false)}67 />68 <Drawer.Content69 asChild70// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from rare-ui
All 13 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Bounce Sidebarbounce-sidebar | rare-ui | Components | Free | 1 dep | |
| Code Blockcode-block | rare-ui | Components | Free | 3 deps | |
| Duration Pickerduration-picker | rare-ui | Components | Free | 5 deps | |
| Emoji Reactionemoji-reaction | rare-ui | Components | Free | 4 deps | |
| Fluid Orbfluid-orb | rare-ui | Components | Free | no deps | |
| Folder Componentfolder-component | rare-ui | Components | Free | 1 dep | |
| GitHub Activitygithub-activity | rare-ui | Components | Free | 1 dep | |
| Gravity Lettersgravity-letters | rare-ui | Components | Free | no deps |
