Drawer

Build hidden sidebars or drawers into your project for navigation, shopping carts, and more with a few classes and our JavaScript plugin. Replaces the old Offcanvas component.

Requires JS
Layer: components
Viewport queries

How it works

Drawer builds on the native <dialog> element and our Dialog component to manage hidden sidebars via JavaScript. These sidebars, or drawers, can appear from the left, right, top, or bottom edge of the viewport. Buttons or anchors are used as triggers that are attached to specific elements you toggle, and data attributes are used to invoke our JavaScript.

  • Drawer shares the same base as our Dialog component, using native <dialog> APIs for focus trapping, backdrop, and top-layer rendering.
  • Use the <dialog> element, not a <div>. Due to how CSS handles animations, don’t apply margin or translate directly to .drawer — wrap it if you need those.
  • Modal by default, or scroll-through — the default opens the drawer modally with a backdrop; set scroll: true to render without a backdrop and without locking body scroll.
  • Built-in backdrop via ::backdrop (modal only) closes the drawer on click; set backdrop: "static" to lock clicks outside, or backdrop: false to hide it.
  • Escape key handling closes the drawer by default; set keyboard: false to disable.
  • Swipe to dismiss — drawer auto-wires a placement-aware swipe (swipe left to close drawer-start in LTR, swipe down to close drawer-bottom, etc.).
  • Responsive placement.sm:drawer, .md:drawer, and up stay drawer-like below their breakpoint and collapse inline above it, making drawers useful as responsive navbars.
  • Only one drawer can be shown at a time (enforced by the data API).
  • Animated open and close — drawer slides back out to its placement-specific off-screen position on close, with the ::backdrop fading alongside it when opened modally. When authoring custom CSS, qualify your [open] rules with :not(.hiding) so the exit transition can fall through to the base state; add .drawer-instant to skip animations.

The animation effect of this component is dependent on the prefers-reduced-motion media query. See the reduced motion section of our accessibility documentation.

Examples

Drawer components

Below is a drawer example that is shown by default (via open and .show on the <dialog>). Drawer includes support for a header with a close button and an optional body class for some initial padding. We suggest that you include drawer headers with dismiss actions whenever possible, or provide an explicit dismiss action.

Drawer
Content for the drawer goes here. You can place just about any Bootstrap component or custom elements here.
HTML
<dialog class="drawer drawer-start show" open tabindex="-1" id="drawer" aria-labelledby="drawerLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerLabel">Drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    Content for the drawer goes here. You can place just about any Bootstrap component or custom elements here.
  </div>
</dialog>

Live demo

Use the buttons below to show and hide a drawer element via JavaScript. You can use a link with the href attribute, or a button with the data-bs-target attribute. In both cases, the data-bs-toggle="drawer" is required.

Link with href
Drawer
Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.
HTML
<a class="btn-solid theme-primary" data-bs-toggle="drawer" href="#drawerExample" role="button" aria-controls="drawerExample">
  Link with href
</a>
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerExample" aria-controls="drawerExample">
  Button with data-bs-target
</button>

<dialog class="drawer drawer-start" tabindex="-1" id="drawerExample" aria-labelledby="drawerExampleLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerExampleLabel">Drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <div>
      Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.
    </div>
    <div class="mt-3">
      <button class="btn-solid theme-secondary" type="button" data-bs-toggle="menu">
        Menu
      </button>
      <div class="menu">
        <a class="menu-item" href="#">Action</a>
        <a class="menu-item" href="#">Another action</a>
        <a class="menu-item" href="#">Something else here</a>
      </div>
    </div>
  </div>
</dialog>

Body scrolling

Scrolling the <body> element is disabled when a drawer and its backdrop are visible. Use the data-bs-scroll attribute to enable <body> scrolling.

Drawer with body scrolling

Try scrolling the rest of the page to see this option in action.

HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerScrolling" aria-controls="drawerScrolling">Enable body scrolling</button>

<dialog class="drawer drawer-start" data-bs-scroll="true" data-bs-backdrop="false" tabindex="-1" id="drawerScrolling" aria-labelledby="drawerScrollingLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerScrollingLabel">Drawer with body scrolling</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <p>Try scrolling the rest of the page to see this option in action.</p>
  </div>
</dialog>

Body scrolling and backdrop

You can also enable <body> scrolling with a visible backdrop.

Backdrop with scrolling

Try scrolling the rest of the page to see this option in action.

HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerWithBothOptions" aria-controls="drawerWithBothOptions">Enable both scrolling & backdrop</button>

<dialog class="drawer drawer-start" data-bs-scroll="true" tabindex="-1" id="drawerWithBothOptions" aria-labelledby="drawerWithBothOptionsLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerWithBothOptionsLabel">Backdrop with scrolling</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <p>Try scrolling the rest of the page to see this option in action.</p>
  </div>
</dialog>

Static backdrop

When backdrop is set to static, the drawer will not close when clicking outside of it.

Drawer
I will not close if you click outside of me.
HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#staticBackdrop" aria-controls="staticBackdrop">
  Toggle static drawer
</button>

<dialog class="drawer drawer-start" data-bs-backdrop="static" tabindex="-1" id="staticBackdrop" aria-labelledby="staticBackdropLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="staticBackdropLabel">Drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <div>
      I will not close if you click outside of me.
    </div>
  </div>
</dialog>

Instant drawer

By default, drawers animate with a slide on open and close. To disable animations, add .drawer-instant to the <dialog> element.

Instant drawer

This drawer doesn’t animate and appears instantly on open and close.

HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#instantDrawer" aria-controls="instantDrawer">
  Toggle instant drawer
</button>

<dialog class="drawer drawer-start drawer-instant" tabindex="-1" id="instantDrawer" aria-labelledby="instantDrawerLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="instantDrawerLabel">Instant drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <p>This drawer doesn’t animate and appears instantly on open and close.</p>
  </div>
</dialog>

Dark drawer

Change the appearance of drawers with utilities to better match them to different contexts like dark navbars. Here we add data-bs-theme="dark" to the .drawer, and it makes all nested elements within use dark mode.

Drawer

Place drawer content here.

HTML
<dialog class="drawer drawer-start show" open tabindex="-1" id="drawerDark" aria-labelledby="drawerDarkLabel" data-bs-theme="dark">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerDarkLabel">Drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <p>Place drawer content here.</p>
  </div>
</dialog>

Translucent drawer

Add .drawer-translucent to the drawer panel to blur and saturate the background. This makes the panel semi-transparent so content behind it shows through.

Translucent drawer
Content for the translucent drawer goes here. The background blurs and saturates whatever is behind it.
HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerTranslucent" aria-controls="drawerTranslucent">
  Toggle translucent drawer
</button>

<dialog class="drawer drawer-start drawer-translucent" tabindex="-1" id="drawerTranslucent" aria-labelledby="drawerTranslucentLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerTranslucentLabel">Translucent drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    Content for the translucent drawer goes here. The background blurs and saturates whatever is behind it.
  </div>
</dialog>

Sheet

Add .drawer-sheet to render the panel flush against the viewport edge. The sheet variant removes the drawer’s inset, border, border-radius, and box-shadow, so it sits edge-to-edge like a traditional offcanvas. It works with any placement.

Sheet drawer
Content for the sheet drawer goes here. It sits flush to the edge with no inset, border, rounded corners, or shadow.
HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerSheet" aria-controls="drawerSheet">
  Toggle sheet drawer
</button>

<dialog class="drawer drawer-bottom drawer-sheet" tabindex="-1" id="drawerSheet" aria-labelledby="drawerSheetLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerSheetLabel">Sheet drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    Content for the sheet drawer goes here. It sits flush to the edge with no inset, border, rounded corners, or shadow.
  </div>
</dialog>

Responsive

Responsive drawer classes hide content outside the viewport from a specified breakpoint and down. Above that breakpoint, the contents within will behave as usual. For example, .lg:drawer hides content in a drawer below the lg breakpoint, but shows the content above the lg breakpoint. Responsive drawer classes are available for each breakpoint.

To make a responsive drawer, replace the .drawer base class with a responsive variant. Close buttons inside the drawer work without an explicit data-bs-target.

Resize your browser to show the responsive drawer toggle.

Responsive drawer

This is content within an .lg:drawer.

HTML
<button class="btn-solid theme-primary lg:d-none" type="button" data-bs-toggle="drawer" data-bs-target="#drawerResponsive" aria-controls="drawerResponsive">Toggle drawer</button>

<div class="alert theme-info d-none lg:d-block mb-3"><p>Resize your browser to show the responsive drawer toggle.</p></div>

<dialog class="lg:drawer drawer-end" tabindex="-1" id="drawerResponsive" aria-labelledby="drawerResponsiveLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerResponsiveLabel">Responsive drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <p class="mb-0">This is content within an <code>.lg:drawer</code>.</p>
  </div>
</dialog>

Placement

There’s no default placement for drawer components, so you must add one of the modifier classes below.

  • .drawer-start places drawer on the left of the viewport (shown above)
  • .drawer-end places drawer on the right of the viewport
  • .drawer-top places drawer on the top of the viewport
  • .drawer-bottom places drawer on the bottom of the viewport
  • .drawer-fullscreen covers the entire viewport

Try the top, right, bottom, and fullscreen examples out below.

Drawer top
...
HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerTop" aria-controls="drawerTop">Toggle top drawer</button>

<dialog class="drawer drawer-top" tabindex="-1" id="drawerTop" aria-labelledby="drawerTopLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerTopLabel">Drawer top</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    ...
  </div>
</dialog>
Drawer right
...
HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerRight" aria-controls="drawerRight">Toggle right drawer</button>

<dialog class="drawer drawer-end" tabindex="-1" id="drawerRight" aria-labelledby="drawerRightLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerRightLabel">Drawer right</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    ...
  </div>
</dialog>
Drawer bottom
...
HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerBottom" aria-controls="drawerBottom">Toggle bottom drawer</button>

<dialog class="drawer drawer-bottom" tabindex="-1" id="drawerBottom" aria-labelledby="drawerBottomLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerBottomLabel">Drawer bottom</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body small">
    ...
  </div>
</dialog>
Fullscreen drawer

This drawer covers the entire viewport, useful for full-page menus or modal-like experiences.

HTML
<button class="btn-solid theme-primary" type="button" data-bs-toggle="drawer" data-bs-target="#drawerFullscreen" aria-controls="drawerFullscreen">Toggle fullscreen drawer</button>

<dialog class="drawer drawer-fullscreen" tabindex="-1" id="drawerFullscreen" aria-labelledby="drawerFullscreenLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerFullscreenLabel">Fullscreen drawer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <p>This drawer covers the entire viewport, useful for full-page menus or modal-like experiences.</p>
  </div>
</dialog>

Add an optional .drawer-footer for action buttons or other content at the bottom of the drawer.

Drawer with footer

Content for the drawer goes here. The footer will stick to the bottom.

HTML
<dialog class="drawer drawer-start show" open tabindex="-1" id="drawerFooter" aria-labelledby="drawerFooterLabel">
  <div class="drawer-header">
    <h5 class="drawer-title" id="drawerFooterLabel">Drawer with footer</h5>
    <button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="none">
    <path fill="currentcolor" d="M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4Z"/>
  </svg>
</button>
  </div>
  <div class="drawer-body">
    <p>Content for the drawer goes here. The footer will stick to the bottom.</p>
  </div>
  <div class="drawer-footer">
    <button type="button" class="btn-solid theme-secondary" data-bs-dismiss="drawer">Close</button>
    <button type="button" class="btn-solid theme-primary">Save changes</button>
  </div>
</dialog>

Accessibility

Since the drawer panel is built on the native <dialog> element, it inherently has the correct dialog role and modal semantics. Be sure to add aria-labelledby="..."—referencing the drawer title—to the <dialog> element.

CSS

Variables

Drawer use local CSS variables on .drawer for real-time customization. Values for the CSS variables are generated from Sass maps unique to each component and applied to the aforementioned class.

// stylelint-disable-next-line scss/dollar-variable-default
$drawer-tokens: defaults(
  (
    --drawer-inset: var(--spacer),
    --drawer-zindex: var(--z-drawer),
    --drawer-width: 400px,
    --drawer-height: 30vh,
    --drawer-padding-x: var(--spacer),
    --drawer-padding-y: var(--spacer),
    --drawer-color: var(--fg-body),
    --drawer-bg: var(--bg-body),
    --drawer-border-width: var(--border-width),
    --drawer-border-color: var(--border-color-translucent),
    --drawer-border-radius: var(--radius-7),
    --drawer-box-shadow: var(--box-shadow-xl),
    --drawer-transition-duration: .3s,
    --drawer-transition-timing: var(--transition-timing-overlay),
    --drawer-title-line-height: 1.5,
    --drawer-backdrop-bg: color-mix(in oklch, var(--bg-body) 25%, transparent),
    --drawer-backdrop-blur: 8px,
  ),
  $drawer-tokens
);

Tokens for the drawer backdrop are available in a separate map as they style the native ::backdrop pseudo-element.

// stylelint-disable-next-line scss/dollar-variable-default
$drawer-backdrop-tokens: defaults(
  (
    --drawer-backdrop-bg: var(--bg-body),
    --drawer-backdrop-opacity: 25%,
    --drawer-backdrop-blur: 8px,
  ),
  $drawer-backdrop-tokens
);

Usage

The drawer plugin is built on the native <dialog> element and utilizes a few classes and attributes to handle the heavy lifting:

  • .drawer on a <dialog> element enables drawer behavior
  • .drawer-start places the drawer on the left
  • .drawer-end places the drawer on the right
  • .drawer-top places the drawer on the top
  • .drawer-bottom places the drawer on the bottom

Add a dismiss button with the data-bs-dismiss="drawer" attribute, which triggers the JavaScript functionality. Be sure to use the <button> element with it for proper behavior across all devices.

Via data attributes

AttributeDescription
data-bs-toggle="drawer"Initializes drawer behavior on the trigger element.
data-bs-targetCSS selector for the <dialog> drawer element to open (or use href on a link).
data-bs-dismiss="drawer"On a dismiss control, closes the drawer when activated.

Toggle

Add data-bs-toggle="drawer" and a data-bs-target or href to the element to automatically assign control of one drawer element. The data-bs-target attribute accepts a CSS selector to apply the drawer to. Be sure to use a <dialog> element with the class drawer.

Dismiss

Dismissal can be achieved with the data-bs-dismiss attribute on a button within the drawer as demonstrated below:

HTML
<button type="button" class="btn-close" data-bs-dismiss="drawer" aria-label="Close"></button>

or on a button outside the drawer using the additional data-bs-target as demonstrated below:

HTML
<button type="button" class="btn-close" data-bs-dismiss="drawer" data-bs-target="#my-drawer" aria-label="Close"></button>

While both ways to dismiss a drawer are supported, keep in mind that dismissing from outside a drawer does not match the ARIA Authoring Practices Guide dialog (modal) pattern. Do this at your own risk.

Via JavaScript

Enable manually with:

JavaScript
const drawerElementList = document.querySelectorAll('dialog.drawer')
const drawerList = [...drawerElementList].map(drawerEl => new bootstrap.Drawer(drawerEl))

Dependencies

The drawer plugin requires the following JavaScript files if you’re building Bootstrap’s JS from source:

FileDescription
js/src/drawer.tsMain drawer component
js/src/base-component.tsBase component class
js/src/dialog-base.tsBase dialog component
js/src/dom/data.tsElement data store
js/src/dom/event-handler.tsEvent handling utilities
js/src/dom/manipulator.tsData attribute manipulation
js/src/dom/selector-engine.tsDOM selector utilities
js/src/util/component-functions.tsShared component helpers
js/src/util/config.tsConfiguration base class
js/src/util/index.tsCore utility functions
js/src/util/swipe.tsSwipe gesture utilities

Options

As options can be passed via data attributes or JavaScript, you can append an option name to data-bs-, as in data-bs-animation="{value}". Make sure to change the case type of the option name from “camelCase” to “kebab-case” when passing the options via data attributes. For example, use data-bs-custom-class="beautifier" instead of data-bs-customClass="beautifier".

All components support a reserved data attribute data-bs-config that can house simple component configuration as a JSON string. When an element has data-bs-config='{"delay":0, "title":123}' and data-bs-title="456" attributes, the final title value will be 456 and the separate data attributes will override values given on data-bs-config. In addition, existing data attributes are able to house JSON values like data-bs-delay='{"show":0,"hide":150}'.

The final configuration object is the merged result of data-bs-config, data-bs-, and js object where the latest given key-value overrides the others.

NameTypeDefaultDescription
backdropboolean or the string statictrueApply a backdrop on body while drawer is open. Alternatively, specify static for a backdrop which doesn’t close the drawer when clicked.
keyboardbooleantrueCloses the drawer when escape key is pressed.
scrollbooleanfalseAllow body scrolling while drawer is open.

Methods

Methods that show or hide a component return a promise. The promise resolves when the transition ends, so await continues at the same moment a shown.bs.* or hidden.bs.* listener runs. The methods still return immediately and never block the caller. A call on a component that is already transitioning does nothing and resolves right away. Learn more in our JavaScript docs.

Activates your content as a drawer element. Accepts an optional options object.

You can create a drawer instance with the constructor, for example:

JavaScript
const bsDrawer = new bootstrap.Drawer('#myDrawer')
MethodDescription
disposeDestroys an element’s drawer.
getInstanceStatic method which allows you to get the drawer instance associated with a DOM element.
getOrCreateInstanceStatic method which allows you to get the drawer instance associated with a DOM element, or create a new one in case it wasn’t initialized.
hideHides a drawer element. Returns a promise that resolves once the drawer element is hidden (i.e. after the hidden.bs.drawer event fires).
showShows a drawer element. Returns a promise that resolves once the drawer element is shown (i.e. after the shown.bs.drawer event fires).
toggleToggles a drawer element to shown or hidden. Returns a promise that resolves once the drawer element is shown or hidden (i.e. after the shown.bs.drawer or hidden.bs.drawer event fires).

Events

Bootstrap’s drawer class exposes a few events for hooking into drawer functionality.

Event typeDescription
hide.bs.drawerThis event is fired immediately when the hide method has been called.
hidden.bs.drawerThis event is fired when a drawer element has been hidden from the user (will wait for CSS transitions to complete).
hidePrevented.bs.drawerThis event is fired when the drawer is shown, its backdrop is static and a click outside of the drawer is performed. The event is also fired when the escape key is pressed and the keyboard option is set to false.
show.bs.drawerThis event fires immediately when the show instance method is called.
shown.bs.drawerThis event is fired when a drawer element has been made visible to the user (will wait for CSS transitions to complete).
JavaScript
const myDrawer = document.getElementById('myDrawer')
myDrawer.addEventListener('hidden.bs.drawer', event => {
  // do something...
})