Navigation and sheets

Sheet

A native sheet with a native header: titles, back, close and actions, detents and a large title.

iOSUISheetPresentationController with a UINavigationBarAndroidTrueSheet with a Material top app barReact Native tier — renders anywhere
iOSUISheetPresentationController with a UINavigationBar
AndroidTrueSheet with a Material top app bar

Import

ts
import {Sheet} from '@hzblj/kara-ui'

Examples

Detents and a large title

tsx
<Sheet detents={[0.6, 1]} onDismiss={close} scrollable visible={open}>
  <Sheet.Header title="Nearby stores" titleStyle="large" trailingItems={closeItem} />
  <Sheet.ScrollView content={{px: 's20'}}>{stores}</Sheet.ScrollView>
</Sheet>

Props

A native sheet — UISheetPresentationController on iOS, Material's bottom sheet on Android — with an optional native header (<Sheet.Header> as a direct child). The React Native tier: it needs no host, and must not sit inside one; native atoms in its content go in an Island.

PropTypeDefaultDescription
children*ReactNode—

The content. A <Sheet.Header> among the direct children becomes the native header instead.

onDismiss*() => void—

The user dismissed it — visible going false does not call this.

visible*boolean—

Presents the sheet while true; going false dismisses it.

bgColorToken'surface.primary'

The sheet's colour. surface.primary by default.

detentsSheetDetent[]FIT_CONTENT

Where the sheet can rest, smallest first. ['auto'] — fit the content — by default.

dimmedbooleantrue

Dims what is behind. On by default.

dismissiblebooleantrue

A swipe down or a tap outside closes it. On by default.

draggablebooleantrue

It follows the finger between detents. On by default.

footerReactElement—

Pinned to the bottom, above the content and the keyboard.

grabberbooleantrue

The drag handle. On by default.

onDetentChange(detentIndex: number) => void—

The sheet moved to another detent — its index in detents.

onPresent() => void—

The sheet finished presenting.

refRef<SheetRef>—

present, dismiss and resize, for driving the sheet imperatively.

scrollablebooleanfalse

The content is a scroll view (<Sheet.ScrollView>) the sheet drives: dragging past its top resizes the sheet, and a header scrolls with the iOS 26 edge effect. Off by default — set it with a scrolling body.

testIDstring—

Test identifier, forwarded to the native sheet.

children*
ReactNode

The content. A <Sheet.Header> among the direct children becomes the native header instead.

onDismiss*
() => void

The user dismissed it — visible going false does not call this.

visible*
boolean

Presents the sheet while true; going false dismisses it.

bg'surface.primary'
ColorToken

The sheet's colour. surface.primary by default.

detentsFIT_CONTENT
SheetDetent[]

Where the sheet can rest, smallest first. ['auto'] — fit the content — by default.

dimmedtrue
boolean

Dims what is behind. On by default.

dismissibletrue
boolean

A swipe down or a tap outside closes it. On by default.

draggabletrue
boolean

It follows the finger between detents. On by default.

footer
ReactElement

Pinned to the bottom, above the content and the keyboard.

grabbertrue
boolean

The drag handle. On by default.

onDetentChange
(detentIndex: number) => void

The sheet moved to another detent — its index in detents.

onPresent
() => void

The sheet finished presenting.

ref
Ref<SheetRef>

present, dismiss and resize, for driving the sheet imperatively.

scrollablefalse
boolean

The content is a scroll view (<Sheet.ScrollView>) the sheet drives: dragging past its top resizes the sheet, and a header scrolls with the iOS 26 edge effect. Off by default — set it with a scrolling body.

testID
string

Test identifier, forwarded to the native sheet.

Sheet.Header

The sheet's header: a NavigationBar with the title and items, and anything else that should stay put above the content (children — a segmented control, a search hint). On iOS 26 a scrollable sheet's content scrolls under it with the system's scroll edge effect; elsewhere it sits above the content.

PropTypeDescription
childrenReactNode

Pinned under the bar.

invertedboolean

Light items and title, for a sheet with a dark or image background.

leadingItemsNavigationBarItem[]

In screen order, from the leading edge.

searchNavigationBarSearch

A search field in place of the title (iOS).

titlestring

The title — in the bar, or above the content with a large titleStyle.

titleStyle'center' | 'large' | 'leading'

center by default.

trailingItemsNavigationBarItem[]

In screen order, toward the trailing edge — the close item, by convention.

children
ReactNode

Pinned under the bar.

inverted
boolean

Light items and title, for a sheet with a dark or image background.

leadingItems
NavigationBarItem[]

In screen order, from the leading edge.

search
NavigationBarSearch

A search field in place of the title (iOS).

title
string

The title — in the bar, or above the content with a large titleStyle.

titleStyle
'center' | 'large' | 'leading'

center by default.

trailingItems
NavigationBarItem[]

In screen order, toward the trailing edge — the close item, by convention.

Sheet.ScrollView

The body of a scrollable sheet: its content starts below an overlaid header, it carries a large title, and it reports its scroll to the sheet.

Also takes 'keyboardShouldPersistTaps' from ScrollViewProps.

PropTypeDescription
children*ReactNode

The scrolling content, after the large title if there is one.

contentResponsiveViewSx

Styles the scrolling content — padding and gap belong here, as with RnScrollView.

onScrollSheetScrollHandler

Called on every scroll event, after the sheet's own listener.

testIDstring

Test identifier, forwarded to the scroll view.

children*
ReactNode

The scrolling content, after the large title if there is one.

content
ResponsiveViewSx

Styles the scrolling content — padding and gap belong here, as with RnScrollView.

onScroll
SheetScrollHandler

Called on every scroll event, after the sheet's own listener.

testID
string

Test identifier, forwarded to the scroll view.

Platform notes

  • React Native tier, on TrueSheet: no host, and never inside one — native atoms in its content go in an Island.
  • Sheet.Header is a slot, not a view: a direct child, built from NavigationBar into a real native header.
  • On iOS 26 a scrollable sheet lays its header over the content, so Sheet.ScrollView pads by the header’s height.
  • onDismiss is the user’s dismissal only — setting visible to false dismisses without calling it.