Touch-friendly bottom sheet component for Bootstrap 5 — supports swipe gestures, backdrop, focus management, and is built with accessibility in mind.
Documentation · Report Bug · Request Feature · Discussions
npm install bootstrap-sheetyarn add bootstrap-sheet<!-- CSS -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap-sheet@latest/dist/css/bootstrap-sheet.min.css"
rel="stylesheet"
/>
<!-- JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap-sheet@latest/dist/js/bootstrap-sheet.min.js"></script><!-- CSS -->
<link
href="https://unpkg.com/bootstrap-sheet@latest/dist/css/bootstrap-sheet.min.css"
rel="stylesheet"
/>
<!-- JavaScript -->
<script src="https://unpkg.com/bootstrap-sheet@latest/dist/js/bootstrap-sheet.min.js"></script>Download the latest release and include the compiled CSS and JavaScript files in your project.
Activate a sheet without writing JavaScript. Set data-bs-toggle="sheet" on a controller element, like a button, along with a data-bs-target="#foo" or href="#foo" to target a specific sheet to toggle.
<!-- Button trigger -->
<button type="button" class="btn btn-primary" data-bs-toggle="sheet" data-bs-target="#mySheet">
Launch sheet
</button>
<!-- Sheet -->
<div
class="sheet"
id="mySheet"
tabindex="-1"
data-bs-backdrop="true"
data-bs-keyboard="true"
data-bs-focus="true"
>
<div class="sheet-handle" data-bs-drag="sheet"></div>
<div class="sheet-header">
<h5 class="sheet-title">Sheet title</h5>
<button type="button" class="btn-close" data-bs-dismiss="sheet" aria-label="Close"></button>
</div>
<div class="sheet-body">
<p>Sheet body text goes here.</p>
</div>
<div class="sheet-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="sheet">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>import BootstrapSheet from 'bootstrap-sheet';
// Create instance (selector or Element accepted)
const sheet = new BootstrapSheet('#mySheet', {
backdrop: true,
keyboard: true,
focus: true,
gestures: true,
});
// Show the sheet
sheet.show();More examples: Live Demo
Options can be passed via data attributes or JavaScript. For data attributes, append the option name to data-bs-, as in data-bs-backdrop="static".
| Name | Type | Default | Description |
|---|---|---|---|
backdrop |
boolean or 'static' |
true |
Includes a backdrop element. Use 'static' for a backdrop that doesn't close the sheet when clicked. |
keyboard |
boolean | true |
Closes the sheet when escape key is pressed. |
focus |
boolean | true |
Puts focus on the sheet when initialized and traps focus within it. |
| Name | Type | Default | Description |
|---|---|---|---|
gestures |
boolean | true |
Enable/disable swipe gestures. |
swipeThreshold |
number | 50 |
Minimum swipe distance (px) to trigger close. |
velocityThreshold |
number | 0.5 |
Minimum velocity (px/ms) to trigger close. |
minCloseDistance |
number | 50 |
Minimum distance (px) for velocity-based close. |
closeThresholdRatio |
number | 0.3 |
Ratio of sheet height (0-1) to trigger close when released. |
| Name | Type | Default | Description |
|---|---|---|---|
animationDuration |
number | 300 |
Animation duration in milliseconds. |
projectionTime |
number | 200 |
Time (ms) to project velocity for momentum-based closing. |
dragResistanceUp |
number | 0.75 |
Resistance when dragging up (0-1, higher = more resistance). |
dragResistanceDown |
number | 0.01 |
Resistance when dragging down (0-1, higher = more resistance). |
All methods are asynchronous and return to the caller as soon as the transition starts.
const sheet = BootstrapSheet.getInstance('#mySheet');| Method | Description |
|---|---|
show() |
Opens the sheet. |
hide() |
Closes the sheet. |
toggle() |
Toggles the sheet visibility. |
dispose() |
Destroys the sheet instance and removes all event listeners. |
getInstance(element) (static) |
Returns the sheet instance associated with a DOM element or null if not initialized. |
getOrCreateInstance(element, config?) (static) |
Gets existing instance or creates a new one if it doesn't exist. |
| Property | Type | Description |
|---|---|---|
isShown |
boolean | Returns true if the sheet is currently visible. |
isTransitioning |
boolean | Returns true if the sheet is currently animating. |
All events are fired at the sheet element itself.
| Event Type | Description |
|---|---|
show.bs.sheet |
Fired immediately when the show() method is called. |
shown.bs.sheet |
Fired when the sheet has been made visible to the user (after CSS transitions complete). |
hide.bs.sheet |
Fired immediately when the hide() method is called. |
hidden.bs.sheet |
Fired when the sheet has finished being hidden from the user (after CSS transitions complete). |
slide.bs.sheet |
Fired continuously during drag/slide gestures. Event detail contains velocity, adjustedY, deltaY, ratio. |
document.getElementById('mySheet').addEventListener('shown.bs.sheet', (event) => {
console.log('Sheet is now visible');
});Customize the appearance by overriding these Sass variables:
// Z-index
$sheet-zindex: 1057 !default;
// Dimensions
$sheet-width: 100vw !default;
$sheet-max-width: 100% !default;
$sheet-max-height: 90vh !default;
// Colors
$sheet-bg: var(--bs-body-bg, #fff) !default;
$sheet-backdrop-bg: rgba(0, 0, 0, 0.5) !default;
$sheet-backdrop-backdrop-filter: blur(2px) !default;
// Transitions
$sheet-transition-duration: 0.3s !default;
$sheet-transition-timing: ease-out !default;
// Handle
$sheet-handle-bg: var(--bs-gray-400, #dee2e6) !default;
$sheet-handle-hover-bg: var(--bs-gray-500, #adb5bd) !default;
$sheet-handle-width: 3rem !default;
$sheet-handle-height: 0.25rem !default;
$sheet-handle-margin: 0.5rem auto !default;
$sheet-handle-hit-area: 2rem !default;
// Spacing
$sheet-padding-x: 1rem !default;
$sheet-padding-y: 1rem !default;
$sheet-header-padding-y: 0.75rem !default;
$sheet-body-padding-y: 1rem !default;
$sheet-footer-padding-y: 0.75rem !default;
// Visual effects
$sheet-box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1) !default;
$sheet-border-width: 1px !default;
$sheet-border-color: var(--bs-border-color, #dee2e6) !default;
$sheet-border-radius: 1rem 1rem 0 0 !default;
// Focus
$sheet-focus-ring-width: 0.25rem !default;
$sheet-focus-ring-color: rgba(13, 110, 253, 0.25) !default;
// Animations
$sheet-shake-distance: 10px !default;
// States
$sheet-disabled-opacity: 0.65 !default;Bootstrap Sheet follows WCAG 2.1 Level AA guidelines:
- ARIA attributes — Automatically applies
role="dialog"andaria-modal="true" - Focus management — Traps focus within the sheet and restores it on close
- Keyboard navigation — Full support for Tab, Shift+Tab, and Escape keys
- Inert background — Uses native
inertattribute witharia-hiddenfallback - Screen reader support — Announces state changes with proper context
- Reduced motion — Respects
prefers-reduced-motionuser preference
Contributions are welcome! Please read our Contributing Guidelines before submitting a Pull Request.
Bootstrap Sheet follows Semantic Versioning. For available versions, see Releases.
Code and documentation © 2025 Sergey Mironov
Code released under the MIT License
Documentation released under Creative Commons Attribution 3.0
Sergey Mironov
- GitHub: @mironovsergey
- Email: sergeymironov@protonmail.com
Made with ❤️ by Sergey Mironov