SwiftUI.js
Components

Sheet

Sheet is a view that presents content as a modal sheet. Sheets slide up from the bottom of the screen and are commonly used for presenting forms, settings, or additional content. When `presentationStyle="fullScreen"`, the same component maps to SwiftUI's `.fullScreenCover()` mental model on the web.

Sheet is a view that presents content as a modal sheet. Sheets slide up from the bottom of the screen and are commonly used for presenting forms, settings, or additional content. When `presentationStyle="fullScreen"`, the same component maps to SwiftUI's `.fullScreenCover()` mental model on the web.

Examples

Basic Usage

Preview unavailable for this example in the static docs build.

Show code
function DefaultSheet() {
  const [isPresented, setIsPresented] = useState(false)

  return (
    <>
      <Button onClick={() => setIsPresented(true)}>Show Sheet</Button>
      <Sheet isPresented={isPresented} onDismiss={() => setIsPresented(false)}>
        <VStack spacing={20}>
          <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Sheet Title</Text>
          <Text>This is a sheet presentation</Text>
          <Button onClick={() => setIsPresented(false)}>Dismiss</Button>
        </VStack>
      </Sheet>
    </>
  )
}

Form Sheet

Preview unavailable for this example in the static docs build.

Show code
function FormSheetComponent() {
  const [isPresented, setIsPresented] = useState(false)

  return (
    <>
      <Button onClick={() => setIsPresented(true)}>Show Form Sheet</Button>
      <Sheet
        isPresented={isPresented}
        onDismiss={() => setIsPresented(false)}
        presentationStyle="formSheet"
      >
        <VStack spacing={20}>
          <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Form Sheet</Text>
          <Text>This is a form sheet style</Text>
          <Button onClick={() => setIsPresented(false)}>Close</Button>
        </VStack>
      </Sheet>
    </>
  )
}

Full Screen

Preview unavailable for this example in the static docs build.

Show code
function FullScreenSheet() {
  const [isPresented, setIsPresented] = useState(false)

  return (
    <>
      <Button onClick={() => setIsPresented(true)}>Show Full Screen</Button>
      <Sheet
        isPresented={isPresented}
        onDismiss={() => setIsPresented(false)}
        presentationStyle="fullScreen"
        showDragIndicator={false}
      >
        <VStack spacing={20} style={{ padding: '20px' }}>
          <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Full Screen</Text>
          <Text>This is a full screen presentation</Text>
          <Button onClick={() => setIsPresented(false)}>Close</Button>
        </VStack>
      </Sheet>
    </>
  )
}

Presentation Styling

Preview unavailable for this example in the static docs build.

Show code
function MaterialSheet() {
  const [isPresented, setIsPresented] = useState(false)

  return (
    <>
      <Button onClick={() => setIsPresented(true)}>Show Material Sheet</Button>
      <Sheet
        isPresented={isPresented}
        onDismiss={() => setIsPresented(false)}
        backgroundStyle="thinMaterial"
        cornerRadius={28}
      >
        <VStack spacing={20} style={{ padding: '20px' }}>
          <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Material Sheet</Text>
          <Text>Thin material background with a custom corner radius.</Text>
          <Button onClick={() => setIsPresented(false)}>Dismiss</Button>
        </VStack>
      </Sheet>
    </>
  )
}

Background Interaction

Preview unavailable for this example in the static docs build.

Show code
function LockedBackdropSheet() {
  const [isPresented, setIsPresented] = useState(false)

  return (
    <>
      <Button onClick={() => setIsPresented(true)}>Show Locked Sheet</Button>
      <Sheet
        isPresented={isPresented}
        onDismiss={() => setIsPresented(false)}
        backgroundInteraction="none"
      >
        <VStack spacing={20} style={{ padding: '20px' }}>
          <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Locked Backdrop</Text>
          <Text>Backdrop taps no longer dismiss this sheet.</Text>
          <Button onClick={() => setIsPresented(false)}>Close explicitly</Button>
        </VStack>
      </Sheet>
    </>
  )
}

Presentation Detents

Preview unavailable for this example in the static docs build.

Show code
function DetentSheet() {
  const [isPresented, setIsPresented] = useState(false)
  const [selectedDetent, setSelectedDetent] = useState<'medium' | 'large'>('medium')

  return (
    <>
      <Button onClick={() => setIsPresented(true)}>Show Detent Sheet</Button>
      <Sheet
        isPresented={isPresented}
        onDismiss={() => setIsPresented(false)}
        presentationDetents={['medium', 'large']}
        selectedDetent={selectedDetent}
        onSelectedDetentChange={(detent) => {
          if (detent === 'medium' || detent === 'large') {
            setSelectedDetent(detent)
          }
        }}
      >
        <VStack spacing={20} style={{ padding: '20px' }}>
          <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Detent Sheet</Text>
          <Text>This sheet starts at the medium detent and cycles when you activate the drag indicator.</Text>
          <Text>Current detent: {selectedDetent}</Text>
          <Button onClick={() => setIsPresented(false)}>Dismiss</Button>
        </VStack>
      </Sheet>
    </>
  )
}

Uncontrolled Detents

Preview unavailable for this example in the static docs build.

Show code
function UncontrolledDetentSheet() {
  const [isPresented, setIsPresented] = useState(false)

  return (
    <>
      <Button onClick={() => setIsPresented(true)}>Show Uncontrolled Detent Sheet</Button>
      <Sheet
        defaultSelectedDetent="medium"
        isPresented={isPresented}
        onDismiss={() => setIsPresented(false)}
        presentationDetents={['medium', 'large']}
      >
        <VStack spacing={20} style={{ padding: '20px' }}>
          <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Uncontrolled Detent Sheet</Text>
          <Text>This sheet resets to its default detent each time it is presented.</Text>
          <Button onClick={() => setIsPresented(false)}>Dismiss</Button>
        </VStack>
      </Sheet>
    </>
  )
}

Interactive Dismiss

Preview unavailable for this example in the static docs build.

Show code
function InteractiveDismissDisabledSheet() {
  const [isPresented, setIsPresented] = useState(false)

  return (
    <>
      <Button onClick={() => setIsPresented(true)}>Show Locked Interaction Sheet</Button>
      <Sheet
        isPresented={isPresented}
        onDismiss={() => setIsPresented(false)}
        interactiveDismissDisabled
      >
        <VStack spacing={20} style={{ padding: '20px' }}>
          <Text style={{ fontSize: 24, fontWeight: 'bold' }}>Interactive Dismiss Disabled</Text>
          <Text>Backdrop taps and Escape no longer dismiss this presentation.</Text>
          <Button onClick={() => setIsPresented(false)}>Close explicitly</Button>
        </VStack>
      </Sheet>
    </>
  )
}

API

PropTypeRequiredDescription
isPresentedbooleanYesWhether the sheet is presented
onDismiss() => voidNoCallback when sheet is dismissed
presentationStyle'pageSheet' | 'formSheet' | 'fullScreen'NoSheet presentation style Default: 'pageSheet'
showDragIndicatorbooleanNoWhether to show drag indicator Default: true
backgroundInteraction'dismiss' | 'none'NoWhether interacting with the backdrop dismisses the sheet. Default: 'dismiss'
backgroundStyle'automatic' | 'thinMaterial' | 'regularMaterial' | 'clear'NoVisual background treatment for the presented sheet. Default: 'automatic'
cornerRadiusnumber | stringNoOverrides the sheet corner radius.
presentationDetentsIPresentationDetent[]NoAvailable detents for the sheet height. Default: ['large']
selectedDetentIPresentationDetentNoCurrently selected detent.
defaultSelectedDetentIPresentationDetentNoInitial detent when used in uncontrolled mode.
onSelectedDetentChange(detent: IPresentationDetent) => voidNoCalled when the selected detent changes.
interactiveDismissDisabledbooleanNoPrevents interactive dismiss affordances like backdrop tap and Escape. Default: false

Inherits additional props from IBaseComponent.

Overview

Sheet is a view that presents content as a modal sheet. Sheets slide up from the bottom of the screen and are commonly used for presenting forms, settings, or additional content. When presentationStyle="fullScreen", the same component maps to SwiftUI's .fullScreenCover() mental model on the web.

SwiftUI Correspondence: Similar to SwiftUI's .sheet() modifier.

Form Sheet

Use form sheet style for forms and input:

Full Screen

Present content in full screen:

Presentation Styling

Customize material treatment and corner radius:

Background Interaction

Prevent backdrop taps from dismissing the sheet:

Presentation Detents

Configure the available sheet heights and choose the initial detent. When more than one detent is available, the drag indicator becomes an explicit control that can cycle between them:

Uncontrolled Detents

Use defaultSelectedDetent when the sheet should reset to a known starting detent each time it is presented:

Interactive Dismiss

Disable backdrop and keyboard dismissal when the presentation must stay locked until an explicit action:

Notes

  • Sheet requires isPresented and onDismiss props
  • Sheet supports different presentation styles
  • Sheet automatically handles dismiss gestures
  • defaultSelectedDetent resets uncontrolled detent state on each new presentation
  • Use Sheet for modal presentations
  • Sheet can contain any React content

Best Practices

  1. Dismiss handling: Always provide onDismiss handler
  2. Presentation style: Choose appropriate style for your content
  3. Drag indicator: Show drag indicator for better UX
  4. Content: Keep sheet content focused and concise
  5. Accessibility: Ensure sheet content is accessible and keyboard navigable

On this page