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
| Prop | Type | Required | Description |
|---|---|---|---|
children | ReactNode | Yes | Your application content |
sheets | ContentMap<TMap> | No | Component map for type registry pattern |
classNames | StacksheetClassNames | No | CSS class overrides for backdrop, panel, and header |
renderHeader | false | (props: HeaderRenderProps) => ReactNode | No | Custom 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.