FamilyDrawer

PreviousNext

A multi-view drawer component with smooth animations, view navigation, and customizable content views

References

Installation

pnpm dlx shadcn@latest add https://cult-ui.com/r/family-drawer.json

Usage

The FamilyDrawer component is a multi-view drawer system that allows you to create navigation between different views within a drawer. It uses Framer Motion for smooth animations and Vaul for drawer functionality.

Basic Example

import { FamilyDrawerAnimatedContent, FamilyDrawerAnimatedWrapper, FamilyDrawerContent, FamilyDrawerRoot, FamilyDrawerTrigger, FamilyDrawerViewContent, useFamilyDrawer, } from "@/components/ui/family-drawer" function DefaultView() { const { setView } = useFamilyDrawer() return ( <> <header className="mb-4 flex h-[72px] items-center border-b border-border pl-2"> <h2 className="text-[19px] font-semibold text-foreground">Menu</h2> </header> <div className="space-y-3"> <button onClick={() => setView("settings")}>Settings</button> <button onClick={() => setView("profile")}>Profile</button> </div> </> ) } function SettingsView() { const { setView } = useFamilyDrawer() return ( <div> <h2>Settings</h2> <button onClick={() => setView("default")}>Back</button> </div> ) } export default function FamilyDrawerDemo() { const views = { default: DefaultView, settings: SettingsView, } return ( <FamilyDrawerRoot views={views}> <FamilyDrawerTrigger>Open Drawer</FamilyDrawerTrigger> <FamilyDrawerContent> <FamilyDrawerAnimatedWrapper> <FamilyDrawerAnimatedContent> <FamilyDrawerViewContent /> </FamilyDrawerAnimatedContent> </FamilyDrawerAnimatedWrapper> </FamilyDrawerContent> </FamilyDrawerRoot> ) }

Components

FamilyDrawerRoot

The root component that provides context and manages drawer state. It accepts a views prop to define the available views.

<FamilyDrawerRoot views={views} defaultView="default" onViewChange={(view) => console.log(view)} > {/* Other FamilyDrawer components */} </FamilyDrawerRoot>

Props:

  • views?: ViewsRegistry - Object mapping view names to React components
  • defaultView?: string - Initial view to display (default: "default")
  • onViewChange?: (view: string) => void - Callback when view changes
  • open?: boolean - Controlled open state
  • defaultOpen?: boolean - Uncontrolled default open state
  • onOpenChange?: (open: boolean) => void - Callback when open state changes

FamilyDrawerTrigger

The trigger button that opens the drawer. Can be used with asChild to compose with other components.

<FamilyDrawerTrigger>Open Drawer</FamilyDrawerTrigger> // Or with asChild <FamilyDrawerTrigger asChild> <Button>Open Drawer</Button> </FamilyDrawerTrigger>

Props:

  • asChild?: boolean - Render as child component
  • className?: string - Additional CSS classes

FamilyDrawerContent

The main content container for the drawer. Handles positioning and animations.

<FamilyDrawerContent> {/* Drawer content */} </FamilyDrawerContent>

Props:

  • className?: string - Additional CSS classes
  • asChild?: boolean - Render as child component

FamilyDrawerAnimatedWrapper

Wrapper component that measures content height for smooth animations.

<FamilyDrawerAnimatedWrapper> {/* Content that needs height measurement */} </FamilyDrawerAnimatedWrapper>

Props:

  • className?: string - Additional CSS classes

FamilyDrawerAnimatedContent

Content wrapper that handles view transitions with opacity animations.

<FamilyDrawerAnimatedContent> {/* Animated content */} </FamilyDrawerAnimatedContent>

FamilyDrawerViewContent

Renders the current view component based on the active view.

<FamilyDrawerViewContent views={views} />

Props:

  • views?: ViewsRegistry - Optional views prop (uses context views if not provided)

FamilyDrawerHeader

A header component with icon, title, and description.

<FamilyDrawerHeader icon={<SettingsIcon />} title="Settings" description="Configure your preferences" />

Props:

  • icon?: ReactNode - Icon element
  • title: string - Header title
  • description?: string - Header description

FamilyDrawerButton

A styled button component for navigation within the drawer.

<FamilyDrawerButton onClick={() => setView("settings")}> Settings </FamilyDrawerButton>

Props:

  • onClick?: () => void - Click handler
  • className?: string - Additional CSS classes
  • asChild?: boolean - Render as child component

FamilyDrawerSecondaryButton

A secondary styled button variant.

<FamilyDrawerSecondaryButton onClick={handleSave}> Save </FamilyDrawerSecondaryButton>

Props:

  • onClick?: () => void - Click handler
  • className?: string - Additional CSS classes
  • asChild?: boolean - Render as child component

FamilyDrawerClose

A close button component for the drawer.

<FamilyDrawerClose />

Props:

  • className?: string - Additional CSS classes
  • asChild?: boolean - Render as child component

FamilyDrawerPortal

Portal component for rendering the drawer outside the DOM hierarchy.

<FamilyDrawerPortal> <FamilyDrawerContent> {/* Content */} </FamilyDrawerContent> </FamilyDrawerPortal>

FamilyDrawerOverlay

The backdrop overlay for the drawer.

<FamilyDrawerOverlay onClick={() => setView("default")} />

Props:

  • className?: string - Additional CSS classes
  • onClick?: () => void - Click handler

useFamilyDrawer Hook

Hook to access drawer context and control view navigation.

function MyView() { const { view, setView, isOpen } = useFamilyDrawer() return ( <div> <p>Current view: {view}</p> <button onClick={() => setView("other")}>Switch View</button> </div> ) }

Returns:

  • view: string - Current active view name
  • setView: (view: string) => void - Function to change the active view
  • isOpen: boolean - Whether the drawer is open
  • opacityDuration: number - Calculated animation duration based on content height
  • elementRef: RefObject - Ref for measuring content height
  • bounds: BoundingBox - Measured bounds of the content

Advanced Usage

Custom Views via Props

You can define views directly in the root component:

const views = { default: DefaultView, settings: SettingsView, profile: ProfileView, } <FamilyDrawerRoot views={views} defaultView="default"> {/* Components */} </FamilyDrawerRoot>

View Navigation

Navigate between views using the setView function from the hook:

function DefaultView() { const { setView } = useFamilyDrawer() return ( <div> <button onClick={() => setView("settings")}>Go to Settings</button> <button onClick={() => setView("profile")}>Go to Profile</button> </div> ) }

Controlled State

Control the drawer and view state externally:

const [open, setOpen] = useState(false) const [view, setView] = useState("default") <FamilyDrawerRoot open={open} onOpenChange={setOpen} defaultView={view} onViewChange={setView} > {/* Components */} </FamilyDrawerRoot>

Customization

The FamilyDrawer component is highly customizable. You can:

  • Customize styles by passing className props to components
  • Define custom views with your own components
  • Control animations by modifying the transition durations
  • Use asChild prop to compose with your own styled components

Accessibility

The FamilyDrawer component includes:

  • Keyboard navigation support (Escape key to close)
  • Proper ARIA attributes via Vaul
  • Focus management
  • Screen reader support

The component builds on Vaul's accessibility features, ensuring a good experience for all users.