Family Drawer React component for Tailwind CSS v4
v1.0.1Updated in 1.2.1
A React bottom drawer that floats above the page and morphs its height between stacked views, inspired by the Family app.
Press the trigger to open a floating bottom drawer with an Options menu. Pick an option and the drawer morphs into that view: its height eases to fit the new content while the old view fades and shrinks away and the new one scales in, with the crossfade timed to how far the height has to travel. Cancel, Reveal or Continue step back to the menu. Drag the drawer down, tap the backdrop, press Escape or use the close button to dismiss it. Buttons press in on tap.
Family Drawer is a free React component in the React overlay components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add family-drawer, together with UIProvider and the npm packages clsx, motion, react-use-measure and vaul.
Add to a project
Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add family-drawerUsage
Import FamilyDrawer from @/components/ui/family-drawer.
import FamilyDrawer from "@/components/ui/family-drawer"
export function Demo() {
return <FamilyDrawer triggerLabel="Wallet options" />
}
// your own views: each one can morph to another view or close the drawer
// <FamilyDrawer
// triggerLabel="Delete project"
// views={{
// default: ({ setView }) => <button onClick={() => setView("confirm")}>Delete</button>,
// confirm: ({ close }) => <button onClick={close}>Yes, delete it</button>,
// }}
// />Props
triggerLabeldefault"Try it out"stringText on the built-in trigger button. Ignored when you pass your own trigger.
titledefault"Options"stringHeading of the built-in menu view, also the drawer's accessible name.
closeLabeldefault"Close"stringAccessible name of the round close button.
defaultViewdefault"default"stringThe view shown first. The built-in views are default, key, phrase and remove; with your own views, any key of views.
sizedefault"md""sm" | "md" | "lg"Maximum width of the drawer: 320px (sm), 361px (md) or 420px (lg). It always keeps a 16px margin on phones.
radiusdefault36numberCorner radius of the drawer in pixels.
accentdefault"#4DAFFF"stringFill of the primary action in the built-in views (Reveal).
dangerdefault"#FF3F40"stringAny CSS color for the destructive action in the built-in views: the Remove Wallet row (tinted to 12%) and the Continue button.
surfacedefault""stringAny CSS color for the drawer panel. Empty uses #FEFFFE light and the popover token dark. The built-in views keep the theme's text and button colors, so pick a surface that suits the theme (or restyle your own views).
showCloseButtondefaulttruebooleanShows the round close button in the top right corner (32px, with a 44px hit area on touch screens).
dismissibledefaulttruebooleanLets a downward drag, a backdrop tap or Escape close the drawer. Turn it off to require the close button or an action inside a view.
defaultOpendefaultfalsebooleanStarts open when uncontrolled. Ignored when open is set.
openbooleanControlled open state. Pass it with onOpenChange to drive the drawer yourself.
onOpenChange(open: boolean) => voidCalled with the next open state from the trigger, the close button, a drag, the backdrop or Escape.
triggerReactNodeYour own trigger element, rendered as the drawer trigger through asChild. Replaces the built-in button.
viewsRecord<string, ReactNode | ((api: { view, setView, close }) => ReactNode)>Your own views keyed by name, replacing the built-in wallet views. A function receives setView to morph to another view and close to dismiss the drawer.
onViewChange(view: string) => voidCalled with the name of the view the drawer morphs to.
classNamestringExtra classes merged onto the drawer panel, for example a different surface color.
Parts
DefaultView
componentThe built-in Options menu: a title row and three option buttons that switch to the key, phrase and remove views.
setView*(view: string) => voidSwitches the drawer to another view.
titledefault"Options"stringThe heading.
dangerdefault"#FF3F40"stringColor of the Remove Wallet row.
Key
componentThe built-in Private Key view: header, three safety notes, Cancel and Reveal.
setView*(view: string) => voidBoth buttons switch back to the default view.
accentdefault"#4DAFFF"stringFill of the Reveal button.
Phrase
componentThe built-in Secret Recovery Phrase view, laid out like Key.
setView*(view: string) => voidBoth buttons switch back to the default view.
accentdefault"#4DAFFF"stringFill of the Reveal button.
RemoveWallet
componentThe built-in confirmation view: a warning header with Cancel and Continue.
setView*(view: string) => voidBoth buttons switch back to the default view.
dangerdefault"#FF3F40"stringFill of the Continue button.
Header
componentThe icon, title and description block at the top of a detail view. Use it in your own views to match.
icon*ReactNodeThe 48px icon above the title.
title*ReactNodeThe 22px heading.
description*ReactNodeThe muted paragraph under it.
Button
componentA 48px gray menu row with an icon and a label, as in the Options view.
children*ReactNodeAn icon and the label.
onClick() => voidCalled on press.
SecondaryButton
componentA 48px pill button for the actions at the bottom of a view; color it with className or style.
children*ReactNodeThe label, optionally with an icon.
onClick() => voidCalled on press.
classNamestringExtra classes, e.g. the fill and text color.
styleCSSPropertiesInline styles, e.g. a backgroundColor.
LockIcon
componentThe 24px lock glyph of the View Private Key row. It takes no props, like the other stock glyphs below.
PhraseIcon
componentThe 24px glyph of the View Recovery Phrase row.
WarningIcon
componentThe 21px warning glyph of the Remove Wallet row.
RecoveryPhraseIcon
componentThe 48px header icon of the Private Key and Recovery Phrase views.
DangerIcon
componentThe 48px red header icon of the Remove Wallet confirmation.
ShieldIcon
componentThe 24px shield glyph of the first safety note in the detail views.
PassIcon
componentThe 24px glyph of the second safety note in the detail views.
BannedIcon
componentThe 24px glyph of the third safety note in the detail views.
FaceIDIcon
componentThe 20px Face ID glyph inside the Reveal button.
CloseIcon
componentThe 12px cross inside the round close button.
CrossIcon
componentA 12px cross glyph, a spare for your own dismiss buttons.
FamilyDrawerApi
typeWhat a view function receives: { view, setView, close }.
FamilyDrawerView
typeA view: plain content, or (api: FamilyDrawerApi) => ReactNode to switch views or close the drawer.
Examples
Confirm a destructive action
Your own views with Header, DangerIcon and SecondaryButton: Delete morphs into a done state, Cancel closes.
Share menu with your own trigger
trigger replaces the built-in button; the stock Button rows make a share menu that morphs into a confirmation.
Controlled
open and onOpenChange drive it from your state; onViewChange reports each view, here with a green accent and the lg width.
Dependencies
Files
- components/ui/family-drawer.tsx
FAQ
Is the React Family Drawer component free?
Yes. The source is free and needs no account: copy it from the Code tab or install it with the CLI.
How do I install Family Drawer?
Run npx wingo-ui@latest add family-drawer. It also adds the Wingo UI item it builds on (UIProvider) and the npm packages clsx, motion, react-use-measure and vaul. With shadcn, run npx shadcn@latest add https://wingo-ui.com/r/family-drawer.json.
See also
More React overlay components
Articles using this component
- React Bottom Sheet for the Web: Snap Points, Drag, Keyboard
Mobile UI in React9 min read
Credits
- •Inspired by the Family app (family.co)