A performant, lightweight, and accessible bottom sheet web component powered by CSS scroll snap and CSS scroll-driven animations. Works with any framework, supports SSR, multiple snap points, and nested scrolling mode.
npm install pure-web-bottom-sheet




A lightweight, framework-agnostic bottom sheet component leveraging CSS scroll snap
and implemented as a Web Component.
Its key features include:
- Native scroll-driven sheet movement and snap points - uses the browser’s own
scroll mechanics instead of JavaScript-driven animations to adjust the sheet position
through CSS scroll snapping
- Near Zero-JavaScript operation on modern browsers - core functionality is
pure CSS
- Framework-agnostic - works with any framework or vanilla HTML
- Easy customization with a simple API
- Accessibility through native elements (Dialog
or Popover API)
supporting touch, keyboard, or mouse scrolling
- Server-side rendering (SSR) compatible with declarative Shadow DOM support
- Cross-browser support - tested on Chrome, Safari, and Firefox (desktop and
mobile)
The component uses CSS scroll snap and CSS scroll-driven animations
for its core functionality. It uses minimal JavaScript for backward compatibility
and optional features, such as swipe-to-dismiss. Relying on browser-driven scrolling
physics ensures a native-like feel across different browsers and a performant implementation
by not relying on JavaScript-driven animation logic.
For server-side rendering or static site generation, the component includes declarative Shadow DOM
templates to avoid flash of unstyled content (FOUC) when displaying the bottom sheet
initially open on page load.
For technical details behind the implementation, read Native-like bottom sheets on the web: the power of modern CSS.
https://github.com/user-attachments/assets/d25beef6-7256-4b7c-93ca-7605f73045b8
``sh`
npm install pure-web-bottom-sheet
#️⃣ Example code - plain non-dismissible bottom sheet
`html
Custom content
`
#️⃣ Example code - modal bottom sheet with dialog integration
`html
Custom content
`
#️⃣ Example code - plain non-dismissible bottom sheet
`astro
---
import { bottomSheetTemplate } from "pure-web-bottom-sheet/ssr";
---
{/ Declarative shadow DOM for SSR support (optional) /}
{/ Snap points /}
Custom content
`
#️⃣ Example code - modal bottom sheet with dialog integration
`astro
---
import { bottomSheetTemplate } from "pure-web-bottom-sheet/ssr";
---
Custom content
`
For React, the library provides wrapper components to make it easier to use the
component and provide SSR support out of the box.
#️⃣ Example code - plain non-dismissible bottom sheet
`tsx
import { BottomSheet } from "pure-web-bottom-sheet/react";
function Example() {
return (
Custom content
#️⃣ Example code - modal bottom sheet with dialog integration
`tsx
import {
BottomSheet,
BottomSheetDialogManager,
} from "pure-web-bottom-sheet/react";import { useRef } from "react";
function Example() {
const dialog = useRef(null);
return (
);
}
`$3
Similarly, for Vue, the library provides wrapper components to make it easier to
use the component and provide SSR support out of the box.
#️⃣ Example code - plain non-dismissible bottom sheet
`vue
Custom header
Custom footer
Custom content
`
#️⃣ Example code - modal bottom sheet with dialog integration
`vue
`▶️ Demos
See live examples and interactive demos
📄 API reference
$3
The
element can be used as a standalone component, optionally
with the HTML Popover API (see the _Examples_ section below), or together with
a dialog element (see element in the following
section). When used without a dialog wrapper element or without the HTML Popover
API, the bottom sheet is non-dismissable. This approach can be useful, e.g., when
using the bottom sheet as an overlay that should always remain visible.#### Example composition
`html
Custom header
Custom footer
Custom content
`#### Attributes
-
content-height
Specifies that the sheet's maximum height is based on the height of its contents.
By default, when this attribute is not set, the sheet's maximum height is based
on the --sheet-max-height property (see below)
> ℹ️ Note: Not applicable when using the nested-scroll attribute
- nested-scroll
Specifies whether the bottom sheet acts as a scrollable container that allows
scrolling its contents independent of the bottom sheet's snap position
- nested-scroll-optimization
Specifies that the bottom sheet uses resize optimization for the nested scroll
mode to avoid reflows during sheet resizing. Only relevant when nested-scroll
is also true. Not relevant for expand-to-scroll mode since it already avoids
reflows.
> ℹ️ Note: This attribute is experimental.
- expand-to-scroll
Specifies that the content of the bottom sheet can only be scrolled after the
bottom sheet has been expanded to its full height
> ℹ️ Note: Only applicable when nested-scroll attribute is also set
- swipe-to-dismiss
Specifies that the bottom sheet can be swiped down to dismiss, and it will have
a snap point on the bottom to snap to close it
> ℹ️ Note: Only relevant when either:
>
> - the is placed inside a