Skip to content

Bottom Sheet

BottomSheet rises from the bottom of the screen. On a wide screen it becomes a centred panel instead, and it can still be dragged. Open it, then drag the handle, press Escape, or click the scrim:

BottomSheetDemo.tsx
import { Heading, Paragraph } from '@hozo/core'
import { BottomSheet, Button, Stack } from '@hozo/ui'
import { useState } from 'react'
export function BottomSheetDemo() {
const [open, setOpen] = useState(false)
return (
<>
<Button tone="neutral" onPress={() => setOpen(true)}>
Filters
</Button>
<BottomSheet
open={open}
onClose={() => setOpen(false)}
accessibilityLabel="Filters"
detents={[0.5, 1]}
>
<Heading level={3} className="text-lg font-bold text-hozo-text">
Filters
</Heading>
<Paragraph className="text-sm text-hozo-text-body">
Drag the handle down to close it, or up to open it fully. Escape and the scrim close it
too.
</Paragraph>
<Stack direction="row" gap="tight">
<Button tone="accent" onPress={() => setOpen(false)}>
Apply
</Button>
<Button tone="quiet" onPress={() => setOpen(false)}>
Cancel
</Button>
</Stack>
</BottomSheet>
</>
)
}
  • open drives it, and onClose is called on Escape, on the scrim, and when a drag ends low enough.
  • detents are the heights it rests at, as fractions of the sheet: [1] by default, or [0.5, 1] for half, then full. defaultDetent chooses where it opens, and dismissBelow where a release closes it.
  • With more than one detent the handle is a button, named by handleAccessibilityLabel (“Resize” by default). Pressing it or using the arrow keys changes the size, so nobody has to drag.
  • It is modal, like Dialog and Drawer, because a sheet that dims the page has already said the page is unavailable.
  • There is no close button: put one in the children when the design wants one visible.