On this page
Offcanvas
Hidden sidebars using a native <dialog>. Open and close
with command / commandfor — no Offcanvas plugin.
| What runs it | JavaScript | |
|---|---|---|
| Bootstrap 5.3 | Offcanvas plugin (same helpers as Modal) | 6.9 KB gzip |
| This repo | dialog with offcanvas placement | 0 KB |
When those APIs are missing,
this page also loads invoker-commands.js (0.8 KB gzip) and dialog-closedby.js (0.5 KB gzip).
See Polyfills.
| Avoid |
|
|---|
How it works
-
command="show-modal"andcommandfor="id"replacedata-bs-toggle="offcanvas". -
command="close"replacesdata-bs-dismiss="offcanvas". -
command="show-popover"opens a non-modal panel so the page can still scroll.popover="manual"has no backdrop (data-bs-scroll="true"+data-bs-backdrop="false").popover="auto"adds a dimmed::backdropand light-dismiss (data-bs-scroll="true"with backdrop). -
The browser draws the backdrop as
::backdrop. Slide animation uses CSS transitions and@starting-styleinstead of.showing/.show/.hiding. -
Default modal offcanvas uses
closedby="any"so backdrop click and Escape request close.closedby="none"replaces a static backdrop. -
commandworks on<button>, not<a href>. -
Native events on the dialog are
closeandcancelinstead of*.bs.offcanvas.
Offcanvas components
A static example of the offcanvas header and body. This preview is not a dialog — use the live demo to open one.
Offcanvas
<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvas" aria-labelledby="offcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasLabel">Offcanvas</h5>
<button type="button" class="btn-close" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
Content for the offcanvas goes here. You can place just about any Bootstrap component or custom elements here.
</div>
</div> Live demo
Use the button to show and hide an offcanvas via command/commandfor on a dialog with the .offcanvas class.
command / commandfor work on
<button> only, so Bootstrap’s “Link with href”
trigger is not available. The dropdown in Bootstrap’s live demo also
needs the Dropdown plugin and is omitted here.
<button type="button" class="btn btn-primary" command="show-modal" commandfor="offcanvasExample">
Toggle offcanvas
</button>
<dialog class="offcanvas offcanvas-start" id="offcanvasExample" closedby="any" aria-labelledby="offcanvasExampleLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasExampleLabel">Offcanvas</h5>
<button type="button" class="btn-close" command="close" commandfor="offcanvasExample" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.
</div>
</dialog> Body scrolling
popover="manual" with command="show-popover" opens a non-modal panel, so the page can still scroll and there is no backdrop.
<button type="button" class="btn btn-primary" command="show-popover" commandfor="offcanvasScrolling">
Enable body scrolling
</button>
<dialog popover="manual" class="offcanvas offcanvas-start" id="offcanvasScrolling" aria-labelledby="offcanvasScrollingLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasScrollingLabel">Offcanvas with body scrolling</h5>
<button type="button" class="btn-close" command="hide-popover" commandfor="offcanvasScrolling" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<p>Try scrolling the rest of the page to see this option in action.</p>
</div>
</dialog> Body scrolling and backdrop
popover="auto" keeps page scrolling and paints a dimmed ::backdrop. Clicking the backdrop (light dismiss) closes the panel.
<button type="button" class="btn btn-primary" command="show-popover" commandfor="offcanvasWithBothOptions">
Enable both scrolling & backdrop
</button>
<dialog popover="auto" class="offcanvas offcanvas-start" id="offcanvasWithBothOptions" aria-labelledby="offcanvasWithBothOptionsLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasWithBothOptionsLabel">Backdrop with scrolling</h5>
<button type="button" class="btn-close" command="hide-popover" commandfor="offcanvasWithBothOptions" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<p>Try scrolling the rest of the page to see this option in action.</p>
</div>
</dialog> Static backdrop
closedby="none" prevents closing on backdrop click and Escape. Dismiss with the close control instead.
<button type="button" class="btn btn-primary" command="show-modal" commandfor="staticBackdrop">
Toggle static offcanvas
</button>
<dialog class="offcanvas offcanvas-start" id="staticBackdrop" closedby="none" aria-labelledby="staticBackdropLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="staticBackdropLabel">Offcanvas</h5>
<button type="button" class="btn-close" command="close" commandfor="staticBackdrop" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
I will not close if you click outside of me.
</div>
</dialog> Dark offcanvas
Set data-bs-theme="dark" on the component (or a parent) instead of the deprecated .text-bg-dark / .btn-close-white utilities.
Offcanvas
Place offcanvas content here.
<div class="offcanvas offcanvas-start" data-bs-theme="dark" tabindex="-1" id="offcanvasDark" aria-labelledby="offcanvasDarkLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasDarkLabel">Offcanvas</h5>
<button type="button" class="btn-close" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<p>Place offcanvas content here.</p>
</div>
</div> Responsive
Responsive offcanvas classes hide content outside the viewport from a specified breakpoint and down. Above that breakpoint, the contents behave as usual. For example, .offcanvas-lg hides content below lg and shows it above.
<button type="button" class="btn btn-primary d-lg-none" command="show-modal" commandfor="offcanvasResponsive">
Toggle offcanvas
</button>
<div class="alert alert-info d-none d-lg-block">Resize your browser to show the responsive offcanvas toggle.</div>
<dialog class="offcanvas-lg offcanvas-end" id="offcanvasResponsive" closedby="any" aria-labelledby="offcanvasResponsiveLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasResponsiveLabel">Responsive offcanvas</h5>
<button type="button" class="btn-close" command="close" commandfor="offcanvasResponsive" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<p class="mb-0">This is content within an <code>.offcanvas-lg</code>.</p>
</div>
</dialog> Placement
There’s no default placement, so you must add .offcanvas-start, .offcanvas-end, .offcanvas-top, or .offcanvas-bottom. Try top, right, and bottom below.
<div class="d-flex flex-wrap gap-2">
<button type="button" class="btn btn-primary" command="show-modal" commandfor="offcanvasTop">Toggle top offcanvas</button>
<button type="button" class="btn btn-primary" command="show-modal" commandfor="offcanvasEnd">Toggle right offcanvas</button>
<button type="button" class="btn btn-primary" command="show-modal" commandfor="offcanvasBottom">Toggle bottom offcanvas</button>
</div>
<dialog class="offcanvas offcanvas-top" id="offcanvasTop" closedby="any" aria-labelledby="offcanvasTopLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasTopLabel">Offcanvas top</h5>
<button type="button" class="btn-close" command="close" commandfor="offcanvasTop" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
...
</div>
</dialog>
<dialog class="offcanvas offcanvas-end" id="offcanvasEnd" closedby="any" aria-labelledby="offcanvasEndLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasEndLabel">Offcanvas right</h5>
<button type="button" class="btn-close" command="close" commandfor="offcanvasEnd" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
...
</div>
</dialog>
<dialog class="offcanvas offcanvas-bottom" id="offcanvasBottom" closedby="any" aria-labelledby="offcanvasBottomLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasBottomLabel">Offcanvas bottom</h5>
<button type="button" class="btn-close" command="close" commandfor="offcanvasBottom" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
...
</div>
</dialog> Accessibility
A modal <dialog class="offcanvas"> traps focus like a modal. Name it with aria-labelledby on the title.
popover="manual" is not modal: the page still scrolls and focus is not trapped. Give that panel a close control. popover="auto" light-dismisses and still does not trap focus.