Pallas UI
DocsComponents
Core Concepts
    • Introduction
    • Getting Started
    • Theming
    • Color Tokens
    • Spacing & Sizing
    • Layout Guide
    • AspectRatio
    • Box
    • Flex
    • Grid
    • Shapes
Previews
    • Accordion
    • Alert
    • Avatar
    • Badge
    • Breadcrumb
    • Button
    • Carousel
    • Checkbox
    • Combobox
    • Command
    • Date Picker
    • Form
    • Input
    • Input OTP
    • Label
    • MenuBar
    • Modal
    • Popover
    • Progress
    • Radio Group
    • Segmented
    • Select
    • Separator
    • Sheet
    • Sidebar
    • Skeleton
    • Slider
    • Spinner
    • Steps
    • Switch
    • Tabs
    • Textarea
    • Toast
    • Tooltip
    • Typography
  1. Components
  2. Sheet

Sheet

A flexible and accessible bottom sheet component for creating slide-out panels and overlays.

Installation

Install the following dependencies

npm install vaul

Copy and paste the following code into your project

import { type Assign, type WithFixedClassName, createStyleContext } from '@pallas-ui/style-context'
import { cx } from '@styled-system/css'
import { type SheetVariantProps, button, sheet } from '@styled-system/recipes'
import type { JsxStyleProps } from '@styled-system/types'
import { forwardRef } from 'react'
import { type DialogProps, Drawer as SheetPrimitive } from 'vaul'
import type { ButtonProps } from '../button'
 
const { withProvider, withContext } = createStyleContext(sheet)
 
export type RootProps = Assign<
  WithFixedClassName<Omit<DialogProps, 'direction'>>,
  SheetVariantProps & JsxStyleProps
>
 
export const Root = withProvider<React.ComponentRef<typeof SheetPrimitive.Root>, RootProps>(
  SheetPrimitive.Root,
  'root',
)
 
export const NestedRoot = withProvider<
  React.ComponentRef<typeof SheetPrimitive.NestedRoot>,
  RootProps
>(SheetPrimitive.NestedRoot, 'nestedRoot')
 
export const Overlay = withContext<
  React.ComponentRef<typeof SheetPrimitive.Overlay>,
  Assign<React.ComponentProps<typeof SheetPrimitive.Overlay>, JsxStyleProps>
>(SheetPrimitive.Overlay, 'overlay')
 
const TriggerComponent = withContext<
  React.ComponentRef<typeof SheetPrimitive.Trigger>,
  Assign<React.ComponentProps<typeof SheetPrimitive.Trigger>, JsxStyleProps & ButtonProps>
>(SheetPrimitive.Trigger, 'trigger')
 
export const Trigger = forwardRef<
  React.ComponentRef<typeof SheetPrimitive.Trigger>,
  Assign<React.ComponentProps<typeof SheetPrimitive.Trigger>, JsxStyleProps & ButtonProps>
>((props, ref) => {
  const [buttonProps, { className, ...rest }] = button.splitVariantProps(props)
  return <TriggerComponent ref={ref} className={cx(button(buttonProps), className)} {...rest} />
})
 
export const Handle = withContext<
  React.ComponentRef<typeof SheetPrimitive.Handle>,
  Assign<React.ComponentProps<typeof SheetPrimitive.Handle>, JsxStyleProps>
>(SheetPrimitive.Handle, 'handle')
 
export const Content = withContext<
  React.ComponentRef<typeof SheetPrimitive.Content>,
  Assign<React.ComponentProps<typeof SheetPrimitive.Content>, JsxStyleProps>
>(SheetPrimitive.Content, 'content')
 
export const Title = withContext<
  React.ComponentRef<typeof SheetPrimitive.Title>,
  Assign<React.ComponentProps<typeof SheetPrimitive.Title>, JsxStyleProps>
>(SheetPrimitive.Title, 'title')
 
export const Description = withContext<
  React.ComponentRef<typeof SheetPrimitive.Description>,
  Assign<React.ComponentProps<typeof SheetPrimitive.Description>, JsxStyleProps>
>(SheetPrimitive.Description, 'description')
 
export const Close = withContext<
  React.ComponentRef<typeof SheetPrimitive.Close>,
  Assign<React.ComponentProps<typeof SheetPrimitive.Close>, JsxStyleProps>
>(SheetPrimitive.Close, 'close')
 
const SheetHeader = ({ ...props }: React.HTMLAttributes<HTMLDivElement>) => <div {...props} />
SheetHeader.displayName = 'SheetHeader'
 
export const Header = withContext<
  React.ComponentRef<typeof SheetHeader>,
  Assign<React.ComponentProps<typeof SheetHeader>, JsxStyleProps>
>(SheetHeader, 'header')
 
const SheetFooter = ({ ...props }: React.HTMLAttributes<HTMLDivElement>) => <div {...props} />
SheetFooter.displayName = 'SheetFooter'
 
export const Footer = withContext<
  React.ComponentRef<typeof SheetFooter>,
  Assign<React.ComponentProps<typeof SheetFooter>, JsxStyleProps>
>(SheetFooter, 'footer')
 
const Sheet = {
  Root,
  NestedRoot,
  Portal: SheetPrimitive.Portal,
  Overlay,
  Handle,
  Content,
  Title,
  Description,
  Close,
  Trigger,
  Header,
  Footer,
}
 
export default Sheet

Update the import paths to match your project setup

Usage

import Sheet from '@/components/ui/sheet'
import { Button } from '@/components/ui/button'
import { Box } from '@styled-system/jsx'
<Sheet.Root>
  <Sheet.Trigger asChild>
    <Button>Open Sheet</Button>
  </Sheet.Trigger>
  <Sheet.Portal>
    <Sheet.Overlay />
    <Sheet.Content>
      <Sheet.Handle />
      <Sheet.Header>
        <Sheet.Title>Sheet Title</Sheet.Title>
        <Sheet.Description>
          This is a description of the sheet.
        </Sheet.Description>
      </Sheet.Header>
      <Box px="padding.inline.md">
        {/* Sheet content goes here */}
      </Box>
      <Sheet.Footer>
        <Sheet.Close asChild>
          <Button variant="outlined">Cancel</Button>
        </Sheet.Close>
        <Button>Continue</Button>
      </Sheet.Footer>
    </Sheet.Content>
  </Sheet.Portal>
</Sheet.Root>

Examples

Basic Sheet

Sheet with Snap Points

Scrollable Sheet

Nested Sheet

API Reference

Sheet.Root

The root sheet element that wraps the entire component.

PropertyTypeDefaultDescriptionOptions
defaultOpenbooleanfalseDefault open state of the sheettrue, false
openboolean-Controls the open state of the sheettrue, false
onOpenChangefunction-Callback when the open state changes-
modalbooleantrueWhether the sheet is modaltrue, false
containerHTMLElementdocument.bodyContainer element for the sheet-
onAnimationEndfunction-Callback when animation ends-
dismissiblebooleantrueWhether the sheet can be dismissedtrue, false
handleOnlybooleanfalseWhether only the handle can be used to dragtrue, false
repositionInputsbooleantrueWhether to reposition inputstrue, false
variantstring-Visual variant of the sheetsnap, scrollable
classNamestring-Custom CSS classes-

Snap Points Properties:

PropertyTypeDefaultDescriptionOptions
snapPoints(string | number)[]-Array of snap points (pixels, percentages, or fractions)-
activeSnapPointstring | number | null-Currently active snap point-
setActiveSnapPointfunction-Function to set the active snap point-
fadeFromIndexnumber-Index from which to fade content-
snapToSequentialPointboolean-Whether to snap to sequential pointstrue, false

Sheet.NestedRoot

Special root component for nested sheets. Use this instead of Sheet.Root when creating sheets inside other sheets.

Same properties as Sheet.Root but optimized for nested usage.

Sheet.Trigger

The element that triggers the sheet to open.

PropertyTypeDefaultDescriptionOptions
asChildbooleanfalseWhether to render as a child elementtrue, false
classNamestring-Custom CSS classes-

Inherits all Button component props when not using asChild.

Sheet.Portal

Portals the sheet content to the document body. Accepts className prop for custom styling.

Sheet.Overlay

The backdrop overlay behind the sheet.

PropertyTypeDefaultDescriptionOptions
asChildbooleanfalseWhether to render as a child elementtrue, false
classNamestring-Custom CSS classes-

Sheet.Content

The main content container of the sheet.

PropertyTypeDefaultDescriptionOptions
asChildbooleanfalseWhether to render as a child elementtrue, false
classNamestring-Custom CSS classes-

Sheet.Handle

Drag handle for dismissing the sheet. Automatically styled based on the sheet variant. Accepts className prop for custom styling.

Sheet.Header

Header section wrapper for title and description. Automatically applies proper spacing and layout. Accepts className prop for custom styling.

Sheet.Footer

Footer section wrapper that sticks to the bottom and contains action buttons. Automatically applies proper spacing and layout. Accepts className prop for custom styling.

Sheet.Title

The sheet title element.

PropertyTypeDefaultDescriptionOptions
asChildbooleanfalseWhether to render as a child elementtrue, false
classNamestring-Custom CSS classes-

Sheet.Description

The sheet description element.

PropertyTypeDefaultDescriptionOptions
asChildbooleanfalseWhether to render as a child elementtrue, false
classNamestring-Custom CSS classes-

Sheet.Close

Button to close the sheet.

PropertyTypeDefaultDescriptionOptions
asChildbooleanfalseWhether to render as a child elementtrue, false
classNamestring-Custom CSS classes-

Built with ❤️ by the carbonteq team. The source code is available on GitHub.

© 2025 Pallas UI. All rights reserved.