React Spring Bottom Sheet
react-spring-bottom-sheet is a React component library designed for creating accessible, animated bottom sheets (also known as bottom drawers or modals) for web applications. It is built upon the `react-spring` library for physics-based animations and `react-use-gesture` for robust gesture control, delivering a smooth and interactive user experience. The current stable version is 3.4.1, which includes support for React 18. Key features include content drag expansion, customizable snap points, and an opt-out focus trap for accessibility. The library differentiates itself by its focus on combining delightful animations with strong accessibility standards through its underlying animation libraries and CSS custom properties for styling. While not adhering to a strict time-based release schedule, the project is actively maintained with updates addressing bug fixes, dependency compatibility, and new features as needed.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'getValue')
cause Often occurs when `react-spring` internal state is accessed before initialization or in a conflicting environment like strict mode or specific bundlers (e.g., Vite/Next.js v13+).fixEnsure `react-spring` and its dependencies are correctly configured for your bundler. Check GitHub issues for workarounds related to `StrictMode` or specific framework versions. Consider alternative packages or forks if the issue persists and is framework-specific. -
Sheet does not animate or close on interaction
cause The `open` prop is not being properly controlled by `useState` and `onDismiss`, or the `onDismiss` callback isn't updating the `open` state correctly.fixVerify that `open` is a boolean state variable and `onDismiss` correctly sets this state variable to `false`. E.g., `const [open, setOpen] = useState(false); <BottomSheet open={open} onDismiss={() => setOpen(false)} />`. -
The bottom sheet appears without any styling or animations
cause The default CSS file `dist/style.css` was not imported, or your build system failed to process the CSS import.fixAdd `import 'react-spring-bottom-sheet/dist/style.css';` to your main application file (e.g., `App.tsx` or `index.tsx`). Ensure your bundler is configured to handle CSS imports. -
Peer dependency 'react@^16.14.0 || 17 || 18' not met
cause Your project's React version does not satisfy the peer dependency requirements of `react-spring-bottom-sheet`.fixUpdate your project's `react` and `react-dom` packages to a compatible version (e.g., `^18.0.0`) or install the package with `--force` or `--legacy-peer-deps` (use with caution as it might lead to unexpected behavior).
Warnings
- gotcha The `open` prop is fully controlled. If `onDismiss` is not provided or does not update the `open` state to `false`, the bottom sheet will not close when users interact with the backdrop or press the Escape key.
- gotcha The component relies on external CSS for styling. For the default look and feel, you must import `react-spring-bottom-sheet/dist/style.css`. Without it, the sheet will lack basic visual structure and animations.
- gotcha When `open` is `false`, the `BottomSheet` component renders only a `@reach/dialog` placeholder and unmounts its children. Ensure your components inside the sheet handle being unmounted and remounted correctly to avoid unexpected state loss or re-initialization.
- gotcha The library heavily uses CSS custom properties (`--rsbs-*`) for styling. Direct manipulation of styles via JavaScript or traditional CSS might be overridden or conflict with these variables, requiring developers to adjust the custom properties.
- gotcha The `blocking={false}` prop disables several accessibility behaviors, including focus-locking. While useful for non-modal scenarios (e.g., a draggable sidebar), it can degrade accessibility for users relying on keyboard navigation or screen readers.
Install
-
npm install react-spring-bottom-sheet -
yarn add react-spring-bottom-sheet -
pnpm add react-spring-bottom-sheet
Imports
- BottomSheet
const BottomSheet = require('react-spring-bottom-sheet').BottomSheetimport { BottomSheet } from 'react-spring-bottom-sheet' - BottomSheetRef
import { BottomSheetRef } from 'react-spring-bottom-sheet'import type { BottomSheetRef } from 'react-spring-bottom-sheet' - style.css
import 'react-spring-bottom-sheet/style.css'
import 'react-spring-bottom-sheet/dist/style.css'
Quickstart
import { useState, useRef } from 'react';
import { BottomSheet, BottomSheetRef } from 'react-spring-bottom-sheet';
import 'react-spring-bottom-sheet/dist/style.css';
function MyBottomSheetComponent() {
const [open, setOpen] = useState(false);
const sheetRef = useRef<BottomSheetRef>(null);
const handleDismiss = () => {
console.log('Sheet dismissed');
setOpen(false);
};
const handleSnapToMax = () => {
if (sheetRef.current) {
sheetRef.current.snapTo(({ maxHeight }) => maxHeight);
}
};
return (
<>
<button onClick={() => setOpen(true)}>Open Bottom Sheet</button>
<BottomSheet
open={open}
onDismiss={handleDismiss}
ref={sheetRef}
snapPoints={({ minHeight, maxHeight }) => [
minHeight,
maxHeight * 0.5,
maxHeight,
]}
header={<div>Sheet Header</div>}
footer={<div>Sheet Footer</div>}
>
<div style={{ padding: '16px' }}>
<h2>Welcome to the Bottom Sheet!</h2>
<p>This is some content inside the sheet. You can drag it up or down to different snap points.</p>
<p>The sheet will automatically adjust its height based on the content or snap to predefined points.</p>
<button onClick={handleSnapToMax}>Expand to full height</button>
</div>
</BottomSheet>
</>
);
}
export default MyBottomSheetComponent;