Bottom sheet
A sheet that rests at a peek or full height and follows your finger.
npm install https://animui.stracture.net/__local/package.tgz- Mobile-first secondary tasks such as details, filters, or share options.
- Content that benefits from a peek height before expanding to nearly full screen.
- Maps and media views where the sheet should be dragged between detents.
- Use dialog for interrupting decisions on any screen size.
- Use drawer for side panels on wide desktop layouts.
- Use popover for small anchored content that should not dim the page.
Installation
Install animui once, then import any component or block from its typed package entry.
React 19 and React DOM 19 are required. The package includes Free and Pro entries, styles and TypeScript declarations.
npm install https://animui.stracture.net/__local/package.tgzLoad the stylesheet once at your app root, then use the typed component import:
import 'animui/styles.css';
import { BottomSheet } from 'animui/bottom-sheet';Read the Code tab for the implementation files and the API reference below for required props.
Download animui 0.3.0 · Agent guideimport { BottomSheet, BottomSheetClose } from "animui/bottom-sheet";import { Button } from "animui/button"; export function TripSheet() { return ( <BottomSheet trigger={<Button>Trip details</Button>} title="Lisbon, 3 nights" description="Oct 12 to Oct 15" detents={[0.4, 0.9]} > <p>Flights, hotel, and bookings.</p> <BottomSheetClose asChild><Button variant="secondary">Done</Button></BottomSheetClose> </BottomSheet> );}Controlled sheet with detent tracking
<BottomSheet open={open} onOpenChange={setOpen} title="Filters" detents={[0.5]} onDetentChange={index => track("detent", index)}> <FilterList /></BottomSheet>API reference
2 parts. The first is the root.
BottomSheet
A modal sheet that rises from the bottom edge and rests at one or more detents, with drag, flick, and keyboard control.
titleRequiredstring–Sheet title, rendered as Dialog.Title.childrenRequiredReactNode–Scrollable sheet content.triggerReactNode–Control that opens the sheet. Rendered with asChild; focus returns to it on close.openboolean–Controlled open state.defaultOpenbooleanfalseInitial open state when uncontrolled.onOpenChange(open: boolean) => void–Called when the sheet opens or closes.descriptionstring–Supporting line, rendered as Dialog.Description.detentsnumber[][0.45, 0.92]Resting heights as fractions of the viewport height.initialDetentnumber0Index into the sorted detents the sheet opens at.onDetentChange(index: number) => void–Called when the sheet settles on a different detent.closeLabelstring"Close"aria-label of the close button.classNamestring–Class on the sheet surface.BottomSheetClose
Radix Dialog.Close for buttons inside the sheet.
...propsComponentPropsWithoutRef<typeof DialogPrimitive.Close>–Radix close props, including asChild.- ArrowUporArrowDown
- On the grabber, moves one detent up or down.
- HomeorEnd
- On the grabber, jumps to the tallest or smallest detent.
- EnterorSpace
- On the grabber, toggles between smallest and tallest detent.
- ArrowDownorPageDownorSpace
- On the sheet, expands to full height first, then scrolls the content.
- Escape
- Closes the sheet.
- Built on Radix Dialog: role="dialog", focus trap, and focus return to the trigger. Initial focus lands on the sheet itself.
- The grabber is a button with aria-expanded and an Expand or Collapse sheet label.
- Detent changes are announced through a polite live region.
- Tabbing into content below the fold expands the sheet so focused elements are visible.
- One motion value drives the sheet: drags follow the finger 1:1, rubber-band past the tallest detent, and releases project velocity to pick a detent or dismiss.
- The backdrop dim is a function of sheet position, so it tracks drags instead of running on a timer.
- Reduced motion jumps between detents and fades the sheet in and out.
- The sheet is min(100%, 36rem) wide and detents are fractions of the dynamic viewport height, so it adapts to mobile browser chrome.
- Below 40rem the header and body use tighter side padding.
- Touch drags on the content move the sheet until it is fully open, then the content scrolls; mouse and pen drag from the header.
- One motion value drives position and backdrop, so drags do not re-render React per frame.
- A ResizeObserver re-fits detents on viewport changes; content is not virtualized, so paginate long lists inside it.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for mobile-first secondary tasks where a peek helps: details, filters, share options. Use dialog for interrupting decisions and drawer for side panels on wide layouts.
- Pass a trigger or control open yourself. Use a single-value detents array for a fixed-height sheet.
The full library index for assistants is at /llms.txt.