๐ŸŽ‰ True Sheet 4.0 is out with a rewritten layout engine. Read the announcement ยท Migration guide
Guides

Detents

Define the sheet's detents, size it to its content, and resize it programmatically.

Detents are the heights the sheet snaps to. The user drags the sheet between them, and you can resize it from code. Pass up to 3 detents to detents, sorted from smallest to largest.

Detents

Each detent is a SheetDetent:

ValueHeight๐ŸŽ๐Ÿค–๐ŸŒ
'auto'Fits the content16+โœ…โœ…
'peek'Collapses to the header, an absolute footer, and the content above a TrueSheetPeek16+โœ…โœ…
numberA fraction (0-1) of the screen heightโœ…โœ…โœ…
const App = () => {
  return (
    <TrueSheet
      detents={['auto', 0.69, 1]}
    >
      <View />
    </TrueSheet>
  )
}

The default is [0.5, 1].

Fixed Heights

A fraction sets the sheet's height relative to the screen: 0.5 is half the screen and 1 is the full height. The content wraps its children like a regular view. To fill the sheet's visible height at each detent, pass flex: 1 via style:

const App = () => {
  return (
    <TrueSheet
      style={{ flex: 1 }}
      detents={[0.5, 1]}
    >
      <View style={{ flex: 1, justifyContent: 'center' }}>
        <Text>Centered</Text>
      </View>
    </TrueSheet>
  )
}

The content resizes in the same frame as the sheet and follows its edge while the user drags, so flex layouts, like a bottom-pinned button, stay in place.

Sizing to the Content

The 'auto' detent sizes the sheet to the content's height. A relative header and footer count toward it too. The sheet resizes when the content changes.

const App = () => {
  return (
    <TrueSheet
      detents={['auto']}
    >
      <View style={{ padding: 24 }}>
        <Text>Sized to fit</Text>
      </View>
    </TrueSheet>
  )
}

Combine it with a fraction to let the user expand the sheet, e.g. ['auto', 1].

Auto with Scrollables

'auto' also works with a ScrollView or FlatList passed to scrollableRef. The sheet sizes to the scroll content and grows with it. When the content is taller than the screen, the sheet stops at its maximum height and the list scrolls. No flex: 1 is needed:

const App = () => {
  const scrollableRef = useRef<FlatList>(null)

  return (
    <TrueSheet detents={['auto']} scrollableRef={scrollableRef}>
      <FlatList
        ref={scrollableRef}
        data={items}
        renderItem={({ item }) => <ItemRow item={item} />}
      />
    </TrueSheet>
  )
}

Lists that wrap their scroll view in a flex: 1 view, like FlashList, still need style={{ flex: 1 }} on the sheet. See the Scrolling guide.

Peek

'peek' collapses the sheet to its header, an absolute footer, and the content above a TrueSheetPeek marker. Use it for map-style sheets that expand from a compact summary. See Peeking Content.

Resizing Programmatically

Call resize with a detent index, not a value.

const App = () => {
  const sheet = useRef<TrueSheet>(null)

  const resize = async () => {
    // Resize to 69%
    await sheet.current?.resize(1)
    console.log('Yay, we are now at 69% ๐Ÿ’ฆ')
  }

  return (
    <TrueSheet name="resizing-sheet" ref={sheet} detents={['auto', 0.69, 1]}>
      <Button onPress={resize} title="Resize" />
    </TrueSheet>
  )
}

You can also do it globally using the related global method.

TrueSheet.resize('resizing-sheet', 1)

present also takes an index, and initialDetentIndex presents the sheet at an index when it mounts. See Present on Mount.

To allow only programmatic resizing, set draggable={false}.

Listening to Detent Changes

onDetentChange fires when the sheet settles at a detent, from a drag or a resize call. It comes with DetentInfoEventPayload: the detent index and its position (Y position on screen).

const App = () => {
  const handleDetentChange = (e: DetentChangeEvent) => {
    const { index, position } = e.nativeEvent
    console.log('Detent index:', index, 'position:', position) โœ…
  }

  return (
    <TrueSheet
      detents={['auto', 0.69, 1]}
      onDetentChange={handleDetentChange}
    >
      <View />
    </TrueSheet>
  )
}

Use the index to look up the detent in your detents array. With detents={['auto', 0.69, 1]}, an index of 1 means the sheet is at 0.69.

To track the sheet's position while it moves, use onPositionChange or the Reanimated integration.

Detent Options

These props take a detent index or change with the detent:

PropUse
initialDetentIndexPresent on mount at this detent
dimmedDetentIndexStart dimming the background at this detent. See Dimming
detentBackgroundsChange the background per detent. See Backgrounds
foldOptionsRest a detent on the hinge of a half-folded iPhone. See Foldables
maxContentHeightCap the sheet's height, whatever the detent
Edit on GitHub

On this page