Adaptive Drawer
ericts-ui/adaptive-drawerFreeComponent
A shadcn Drawer that measures panel content and animates height changes.
Live preview
live · rendered by the registry
Rendered by ericts-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://ui.ericts.com/r/adaptive-drawer.jsonSource
1"use client";23import * as React from "react";4import { X } from "lucide-react";5import {6 AnimatePresence,7 motion,8 MotionConfig,9 useReducedMotion,10 type HTMLMotionProps,11} from "motion/react";1213import { buttonVariants } from "@/components/ui/button";14import {15 Drawer,16 DrawerClose,17 DrawerContent,18 DrawerDescription,19 DrawerTitle,20 DrawerTrigger,21} from "@/components/ui/drawer";22import { cn } from "@/lib/utils";2324type MotionTransition = NonNullable<HTMLMotionProps<"div">["transition"]>;2526const minPanelDuration = 0.15;27const maxPanelDuration = 0.27;28const drawerExitResetDelay = 550;29const heightChangeDurationDivisor = 500;30const heightChangeThreshold = 0.5;3132export type AdaptiveDrawerControls = {33 activePanel: string;34 setPanel: (panel: string) => void;35 close: () => void;36};3738export type AdaptiveDrawerPanel = {39 id: string;40 title: React.ReactNode;41 description?: React.ReactNode;42 content:43 | React.ReactNode44 | ((controls: AdaptiveDrawerControls) => React.ReactNode);45};4647export type AdaptiveDrawerProps = {48 panels: AdaptiveDrawerPanel[];49 panel?: string;50 defaultPanel?: string;51 onPanelChange?: (panel: string) => void;52 resetOnClose?: boolean;53 title?: React.ReactNode;54 description?: React.ReactNode;55 trigger?: React.ReactNode;56 triggerLabel?: React.ReactNode;57 closeLabel?: string;58 open?: boolean;59 defaultOpen?: boolean;60 onOpenChange?: (open: boolean) => void;61 drawerClassName?: string;62 contentClassName?: string;63 heightTransition?: MotionTransition;64 panelTransition?: MotionTransition;65};6667export function AdaptiveDrawer({68 panels,69 panel,70 defaultPanel,71 onPanelChange,72 resetOnClose = true,73 title = "Adaptive drawer",74 description,75 trigger,76 triggerLabel = "Open drawer",77 closeLabel = "Close drawer",78 open,79 defaultOpen = false,80 onOpenChange,81 drawerClassName,82 contentClassName,83 heightTransition,84 panelTransition,85}: AdaptiveDrawerProps) {86 const fallbackPanel = defaultPanel ?? panels[0]?.id ?? "";87 const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);88 const [uncontrolledPanel, setUncontrolledPanel] =89 React.useState(fallbackPanel);90 const [height, setHeight] = React.useState<number | null>(null);91 const [panelDuration, setPanelDuration] =92 React.useState(minPanelDuration);93 const [contentElement, setContentElement] =94 React.useState<HTMLDivElement | null>(null);95 const frameRef = React.useRef<number | null>(null);96// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from ericts-ui
All 38 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Check Animationcheck-animation | ericts-ui | Components | Free | no deps · 2 files | |
| Context Cursorcontext-cursor | ericts-ui | Components | Free | 1 dep | |
| Copy Buttoncopy-button | ericts-ui | Components | Free | 2 deps | |
| Expandable Dialogexpandable-modal | ericts-ui | Components | Free | 1 dep | |
| Expandable Tabsexpandable-tabs | ericts-ui | Components | Free | 1 dep | |
| Expandable Toolbarexpandable-toolbar | ericts-ui | Components | Free | 1 dep | |
| Expanding Panelexpanding-panel | ericts-ui | Components | Free | 2 deps | |
| Expanding Segmented Tabsexpanding-segmented-tabs | ericts-ui | Components | Free | 1 dep |
