Bootstrap 5 Offcanvas Tutorial
Sliding sidebar panels for menus, carts, filters, and contextual content.
What is Offcanvas?
Offcanvas is a sidebar component that slides in from the edge of the viewport. It's similar to modals but is typically used as a sidebar navigation menu, especially on mobile devices. Unlike modals that appear centered, offcanvas panels slide in from the left, right, top, or bottom of the screen.
Common use cases:
- Mobile-responsive navigation menus
- Shopping carts in e-commerce sites
- Filter panels for product listings
- Settings or preferences panels
- Additional content without leaving the current page
1. Basic Offcanvas Sidebar
The simplest offcanvas implementation with a button trigger.
<!-- Button to open the offcanvas sidebar -->
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#demo">
Open Offcanvas Sidebar
</button>
<!-- Offcanvas Sidebar -->
<div class="offcanvas offcanvas-start" id="demo">
<div class="offcanvas-header">
<h1 class="offcanvas-title">Heading</h1>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>Some text lorem ipsum.</p>
<p>Some text lorem ipsum.</p>
<button class="btn btn-secondary" type="button">A Button</button>
</div>
</div>
Component Structure:
| Class | Purpose |
|---|---|
.offcanvas | Main container (hidden by default) |
.offcanvas-start | Positions sidebar on the left (400px wide) |
.offcanvas-header | Top section with title and close button |
.offcanvas-title | Title styling with proper margins |
.offcanvas-body | Scrollable content area with padding |
data-bs-toggle="offcanvas" | Triggers the offcanvas JavaScript |
data-bs-dismiss="offcanvas" | Closes the offcanvas |
2. Offcanvas Placements
You can position the offcanvas panel on any edge of the viewport.
Left Side (Default)
<div class="offcanvas offcanvas-start" id="offcanvasLeft">
<!-- content -->
</div>Right Side
<button class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#offcanvasRight">
Open Right Sidebar
</button>
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasRight">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Right Sidebar</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>This sidebar slides in from the right edge.</p>
</div>
</div>Top Side
<button class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#offcanvasTop">
Open Top Panel
</button>
<div class="offcanvas offcanvas-top" tabindex="-1" id="offcanvasTop">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Top Panel</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>This panel slides in from the top edge.</p>
</div>
</div>Bottom Side
<button class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#offcanvasBottom">
Open Bottom Panel
</button>
<div class="offcanvas offcanvas-bottom" tabindex="-1" id="offcanvasBottom">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Bottom Panel</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>This panel slides in from the bottom edge.</p>
</div>
</div>3. Offcanvas with Backdrop and Scrolling Options
Control whether the background is dimmed and whether the main page can scroll while the offcanvas is open.
Enable Body Scrolling (No Backdrop)
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasScrolling">
Enable Body Scrolling
</button>
<div class="offcanvas offcanvas-start" data-bs-scroll="true" data-bs-backdrop="false" tabindex="-1" id="offcanvasScrolling">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Scrolling Enabled</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>Try scrolling the rest of the page - the main content scrolls while the offcanvas is open.</p>
<p>The backdrop is disabled, so clicking outside won't close this panel.</p>
</div>
</div>Default Backdrop (Body Scroll Disabled)
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasWithBackdrop">
Enable Backdrop (Default)
</button>
<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasWithBackdrop">
<div class="offcanvas-header">
<h5 class="offcanvas-title">With Backdrop</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>Background is dimmed.</p>
<p>Main page scrolling is disabled.</p>
<p>Click the backdrop to close this panel.</p>
</div>
</div>Both Options (Scroll + Backdrop)
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasWithBothOptions">
Enable Both Scrolling & Backdrop
</button>
<div class="offcanvas offcanvas-start" data-bs-scroll="true" tabindex="-1" id="offcanvasWithBothOptions">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Backdrop with Scrolling</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>Try scrolling the rest of the page to see this option in action.</p>
<p>The backdrop is visible, but the main page can still scroll.</p>
</div>
</div>Static Backdrop (Click Outside Won't Close)
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#staticBackdrop">
Toggle Static Offcanvas
</button>
<div class="offcanvas offcanvas-start" data-bs-backdrop="static" tabindex="-1" id="staticBackdrop">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Static Backdrop</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<div>I won't close if you click outside me.</div>
<p class="mt-2">You must use the close button or press ESC to dismiss me.</p>
</div>
</div>
Option Summary:
| Attribute | Values | Default | Description |
|---|---|---|---|
data-bs-scroll | true / false | false | Allows body scrolling while offcanvas is open |
data-bs-backdrop | true / false / static | true | Controls backdrop visibility and behavior |
5. Dark Offcanvas Theme
For dark navigation bars or different visual contexts.
<!-- Dark themed offcanvas -->
<div class="offcanvas offcanvas-start text-bg-dark" id="offcanvasDark">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Dark Sidebar</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<ul class="nav nav-pills flex-column">
<li class="nav-item">
<a href="#" class="nav-link text-white">Dashboard</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link text-white">Profile</a>
</li>
<li class="nav-item">
<a href="#" class="nav-link text-white">Settings</a>
</li>
</ul>
</div>
</div>
Note: Use
btn-close-white for the close button to ensure visibility on dark backgrounds.6. Offcanvas with Rich Content
Offcanvas can contain any Bootstrap components - forms, lists, dropdowns, accordions, etc.
Shopping Cart Offcanvas Example
<button class="btn btn-primary position-relative" type="button" data-bs-toggle="offcanvas" data-bs-target="#cartOffcanvas">
Cart
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">3</span>
</button>
<div class="offcanvas offcanvas-end" tabindex="-1" id="cartOffcanvas" style="width: 400px;">
<div class="offcanvas-header bg-primary text-white">
<h5 class="offcanvas-title">Shopping Cart</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<!-- Cart Items -->
<div class="list-group list-group-flush">
<div class="list-group-item d-flex justify-content-between align-items-center">
<div>
<h6 class="mb-0">Product Name 1</h6>
<small class="text-muted">$29.99</small>
</div>
<div>
<button class="btn btn-sm btn-outline-danger">Remove</button>
</div>
</div>
<div class="list-group-item d-flex justify-content-between align-items-center">
<div>
<h6 class="mb-0">Product Name 2</h6>
<small class="text-muted">$49.99</small>
</div>
<div>
<button class="btn btn-sm btn-outline-danger">Remove</button>
</div>
</div>
<div class="list-group-item d-flex justify-content-between align-items-center">
<div>
<h6 class="mb-0">Product Name 3</h6>
<small class="text-muted">$19.99</small>
</div>
<div>
<button class="btn btn-sm btn-outline-danger">Remove</button>
</div>
</div>
</div>
<!-- Cart Summary -->
<div class="mt-4">
<div class="d-flex justify-content-between">
<strong>Subtotal:</strong>
<span>$99.97</span>
</div>
<div class="d-flex justify-content-between mt-2">
<strong>Shipping:</strong>
<span>$5.00</span>
</div>
<hr>
<div class="d-flex justify-content-between">
<strong>Total:</strong>
<strong class="text-primary">$104.97</strong>
</div>
<div class="d-grid gap-2 mt-4">
<button class="btn btn-primary">Proceed to Checkout</button>
<button class="btn btn-outline-secondary" data-bs-dismiss="offcanvas">Continue Shopping</button>
</div>
</div>
</div>
</div>
Filter Panel Offcanvas Example
<button class="btn btn-outline-secondary" type="button" data-bs-toggle="offcanvas" data-bs-target="#filterOffcanvas">
<i class="bi bi-funnel"></i> Filters
</button>
<div class="offcanvas offcanvas-start" tabindex="-1" id="filterOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Filter Products</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<form>
<!-- Price Range -->
<div class="mb-4">
<label class="form-label fw-bold">Price Range</label>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="price1">
<label class="form-check-label" for="price1">Under $25</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="price2">
<label class="form-check-label" for="price2">$25 - $50</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="price3">
<label class="form-check-label" for="price3">$50 - $100</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="price4">
<label class="form-check-label" for="price4">Over $100</label>
</div>
</div>
<!-- Categories -->
<div class="mb-4">
<label class="form-label fw-bold">Categories</label>
<div class="form-check">
<input class="form-check-input" type="radio" name="category">
<label class="form-check-label">Electronics</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="category">
<label class="form-check-label">Clothing</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="category">
<label class="form-check-label">Home & Garden</label>
</div>
</div>
<!-- Rating -->
<div class="mb-4">
<label class="form-label fw-bold">Rating</label>
<select class="form-select">
<option>4 stars & up</option>
<option>3 stars & up</option>
<option>2 stars & up</option>
<option>1 star & up</option>
</select>
</div>
<div class="d-grid gap-2">
<button type="submit" class="btn btn-primary">Apply Filters</button>
<button type="reset" class="btn btn-outline-secondary">Reset All</button>
</div>
</form>
</div>
</div>
7. JavaScript Methods and Events
Control offcanvas programmatically with JavaScript.
Basic JavaScript Control
<button class="btn btn-success" id="openBtn">Open via JS</button>
<button class="btn btn-warning" id="toggleBtn">Toggle via JS</button>
<button class="btn btn-danger" id="closeBtn">Close via JS</button>
<div class="offcanvas offcanvas-start" id="jsOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">JavaScript Controlled</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>This offcanvas is controlled entirely with JavaScript.</p>
<p>Check the console for event logs.</p>
</div>
</div>
<script>
// Get the offcanvas element
const offcanvasElement = document.getElementById('jsOffcanvas');
// Initialize offcanvas instance
const myOffcanvas = new bootstrap.Offcanvas(offcanvasElement);
// Open offcanvas
document.getElementById('openBtn').addEventListener('click', () => {
myOffcanvas.show();
});
// Toggle offcanvas
document.getElementById('toggleBtn').addEventListener('click', () => {
myOffcanvas.toggle();
});
// Close offcanvas
document.getElementById('closeBtn').addEventListener('click', () => {
myOffcanvas.hide();
});
</script>
Offcanvas Events
<button class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#eventOffcanvas">
Open Offcanvas with Events
</button>
<div class="offcanvas offcanvas-start" id="eventOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Event Demo</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<div id="eventLog" class="alert alert-info">
Events will appear here
</div>
</div>
</div>
<script>
const eventOffcanvas = document.getElementById('eventOffcanvas');
const eventLog = document.getElementById('eventLog');
function logEvent(eventName) {
eventLog.innerHTML += `<div>${eventName} triggered</div>`;
}
eventOffcanvas.addEventListener('show.bs.offcanvas', () => logEvent('show.bs.offcanvas (starts show)'));
eventOffcanvas.addEventListener('shown.bs.offcanvas', () => logEvent('shown.bs.offcanvas (animation complete)'));
eventOffcanvas.addEventListener('hide.bs.offcanvas', () => logEvent('hide.bs.offcanvas (starts hide)'));
eventOffcanvas.addEventListener('hidden.bs.offcanvas', () => logEvent('hidden.bs.offcanvas (animation complete)'));
</script>
Available Events:
| Event | Description |
|---|---|
show.bs.offcanvas | Fires immediately when the show method is called |
shown.bs.offcanvas | Fires when the offcanvas has been made visible |
hide.bs.offcanvas | Fires immediately when the hide method is called |
hidden.bs.offcanvas | Fires when the offcanvas has been hidden |
8. JavaScript Options
// Initialize with custom options
const offcanvas = new bootstrap.Offcanvas(document.getElementById('myOffcanvas'), {
backdrop: 'static', // Prevents closing when clicking backdrop
keyboard: false, // Prevents closing when ESC key is pressed
scroll: true // Allows body scrolling while offcanvas is open
});
// Or via data attributes
// <div class="offcanvas" data-bs-backdrop="static" data-bs-keyboard="false" data-bs-scroll="true">
Available Options:
| Option | Type | Default | Description |
|---|---|---|---|
backdrop | boolean or 'static' | true | Includes backdrop element. 'static' prevents closing on click |
keyboard | boolean | true | Closes offcanvas when ESC key is pressed |
scroll | boolean | false | Allows body scrolling while offcanvas is open |
9. Custom Styling Examples
Custom Width Offcanvas
<style>
/* Custom width for specific offcanvas */
#wideOffcanvas {
width: 500px;
}
/* Responsive widths */
@media (max-width: 768px) {
#wideOffcanvas {
width: 85vw;
}
}
</style>
<div class="offcanvas offcanvas-start" id="wideOffcanvas">
<!-- content -->
</div>Offcanvas with Custom Animation
<style>
/* Custom animation - slide in slower */
.offcanvas.slow-slide {
transition: transform 0.5s ease-in-out;
}
/* Custom animation - bounce effect */
.offcanvas.bounce {
transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
</style>
<div class="offcanvas offcanvas-start slow-slide" id="slowOffcanvas">
<!-- content -->
</div>Rounded Corners Offcanvas
<style>
.offcanvas.rounded-offcanvas {
border-radius: 16px 0 0 16px;
}
.offcanvas-start.rounded-offcanvas {
border-radius: 0 16px 16px 0;
}
</style>
<div class="offcanvas offcanvas-start rounded-offcanvas" id="roundedOffcanvas">
<!-- content -->
</div>Quick Reference Table
| Class | Purpose |
|---|---|
.offcanvas | Main container |
.offcanvas-start | Position - left side |
.offcanvas-end | Position - right side |
.offcanvas-top | Position - top edge |
.offcanvas-bottom | Position - bottom edge |
.offcanvas-header | Top section with title and close button |
.offcanvas-title | Title text styling |
.offcanvas-body | Scrollable content area |
.offcanvas.show | Shows the offcanvas (toggled via JS) |
data-bs-toggle="offcanvas" | Triggers offcanvas |
data-bs-dismiss="offcanvas" | Closes offcanvas |
Complete Demo HTML Page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bootstrap 5 Offcanvas - Complete Tutorial</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.0/font/bootstrap-icons.css">
<style>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 2rem;
}
.demo-section {
background: white;
border-radius: 15px;
padding: 2rem;
margin-bottom: 2rem;
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.demo-title {
color: #333;
border-left: 4px solid #0d6efd;
padding-left: 1rem;
margin-bottom: 1.5rem;
}
</style>
</head>
<body>
<div class="container">
<h1 class="text-center mb-5 display-4 text-white">
<i class="bi bi-layout-sidebar"></i> Bootstrap 5 Offcanvas Tutorial
</h1>
<!-- Section 1: Basic Offcanvas -->
<div class="demo-section">
<h2 class="demo-title">1. Basic Offcanvas Sidebar</h2>
<button class="btn btn-primary" type="button" data-bs-toggle="offcanvas" data-bs-target="#basicOffcanvas">
Open Sidebar
</button>
<div class="offcanvas offcanvas-start" id="basicOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Basic Sidebar</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>This is a basic offcanvas sidebar that slides in from the left.</p>
<button class="btn btn-secondary" data-bs-dismiss="offcanvas">Close</button>
</div>
</div>
</div>
<!-- Section 2: Different Placements -->
<div class="demo-section">
<h2 class="demo-title">2. Offcanvas Placements</h2>
<div class="d-flex gap-2 flex-wrap">
<button class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#rightOffcanvas">Right Side</button>
<button class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#topOffcanvas">Top Panel</button>
<button class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#bottomOffcanvas">Bottom Panel</button>
</div>
</div>
<!-- Section 3: Responsive Navbar -->
<div class="demo-section">
<h2 class="demo-title">3. Responsive Offcanvas Navbar</h2>
<nav class="navbar navbar-expand-lg navbar-light bg-light rounded">
<div class="container-fluid">
<a class="navbar-brand" href="#">MyBrand</a>
<button class="btn btn-primary d-lg-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#responsiveOffcanvas">
Menu
</button>
<div class="d-none d-lg-flex">
<a href="#" class="nav-link">Home</a>
<a href="#" class="nav-link">About</a>
<a href="#" class="nav-link">Contact</a>
</div>
</div>
</nav>
</div>
</div>
<!-- Offcanvas Components -->
<div class="offcanvas offcanvas-end" id="rightOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Right Sidebar</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>This sidebar slides in from the right edge.</p>
</div>
</div>
<div class="offcanvas offcanvas-top" id="topOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Top Panel</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>This panel slides in from the top.</p>
</div>
</div>
<div class="offcanvas offcanvas-bottom" id="bottomOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Bottom Panel</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>This panel slides in from the bottom.</p>
</div>
</div>
<div class="offcanvas offcanvas-end" tabindex="-1" id="responsiveOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Navigation Menu</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav">
<li class="nav-item"><a class="nav-link" href="#" data-bs-dismiss="offcanvas">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#" data-bs-dismiss="offcanvas">About</a></li>
<li class="nav-item"><a class="nav-link" href="#" data-bs-dismiss="offcanvas">Services</a></li>
<li class="nav-item"><a class="nav-link" href="#" data-bs-dismiss="offcanvas">Contact</a></li>
</ul>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>