Stacksheetv1.1.4

StacksheetProvider

Provider component that renders the sheet stack UI.

Overview

StacksheetProvider is the component returned by createStacksheet(). It renders the sheet stack UI (backdrop, panels, headers) and provides React context for the hooks.

<StacksheetProvider>
  <App />
</StacksheetProvider>

Props

PropTypeRequiredDescription
childrenReactNodeYesYour application content
sheetsContentMap<TMap>NoComponent map for type registry pattern
classNamesStacksheetClassNamesNoCSS class overrides for backdrop, panel, and header
renderHeaderfalse | (props: HeaderRenderProps) => ReactNodeNoCustom header renderer, or false for composable mode

Styling props

Override styles with classNames and renderHeader:

<StacksheetProvider
  classNames={{
    backdrop: "my-backdrop",
    panel: "my-panel",
  }}
  renderHeader={({ isNested, onBack, onClose, side }) => (
    <MyCustomHeader
      isNested={isNested}
      onBack={onBack}
      onClose={onClose}
      side={side}
    />
  )}
>
  <App />
</StacksheetProvider>

See Styling for full details.

Composable mode

Set renderHeader={false} to disable the auto header and scroll wrapper. Your sheet components then use Sheet.* parts to build custom layouts:

<StacksheetProvider renderHeader={false}>
  <App />
</StacksheetProvider>

See Composable Parts for the full guide, parts reference, and accessibility details.

Content components

Sheet components are regular React components. They receive their data as props. If the component needs to close the sheet, it calls useSheet().close():

function UserProfile({ userId }: { userId: string }) {
  const { close } = useSheet();
  return (
    <div>
      <h2>User {userId}</h2>
      <button onClick={close}>Done</button>
    </div>
  );
}

DOM anatomy

When rendered, the provider produces:

<StacksheetProvider>
  {children}                          <- your app content
  <Portal>                            <- Radix Portal (renders at document.body)
    <motion.div />                    <- backdrop overlay (modal only)
    <RemoveScroll>                    <- scroll lock wrapper (modal only)
      <div style="fixed; overflow:hidden">
        <AnimatePresence>
          <FocusTrap>                 <- focus trap (modal only)
            <motion.div>             <- panel (slides from side)
              <DefaultHeader />      <- or renderHeader()
              <div>                  <- scrollable content area
                <ContentComponent /> <- your component
              </div>
            </motion.div>
          </FocusTrap>
        </AnimatePresence>
      </div>
    </RemoveScroll>
  </Portal>
</StacksheetProvider>

In composable mode (renderHeader={false}), the panel contains your component directly — no auto header or scroll wrapper:

<motion.div>                         <- panel
  <ContentComponent />               <- uses Sheet.* parts for layout
</motion.div>

In non-modal mode (modal: false), the FocusTrap, RemoveScroll, and backdrop are omitted.

On this page