Skip to main content Skip to docs navigation

Create hidden navigation panels, shopping carts, and contextual sidebars that slide in from any edge of the viewport with Chassis CSS's offcanvas component.

Overview

Offcanvas creates slide-out panels that appear from any edge of the viewport, perfect for navigation menus, shopping carts, filters, or contextual information that needs to be accessible but not always visible. These panels maintain focus and accessibility while providing smooth animations and flexible positioning.

Built with responsive design principles and keyboard navigation support, offcanvas panels offer flexible sizing options, backdrop controls, and seamless integration with other Chassis CSS components. Each offcanvas consists of:

  • Offcanvas container controls visibility and positioning
  • Offcanvas header provides structure with title and close button
  • Offcanvas body contains the main panel content
Offcanvas
Content for the offcanvas goes here. You can place just about any Chassis CSS component or custom elements here.
html
<div class="offcanvas offcanvas-start show" tabindex="-1" id="offcanvas" aria-labelledby="offcanvasLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasLabel">Offcanvas</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    Content for the offcanvas goes here. You can place just about any Chassis CSS component or custom elements here.
  </div>
</div>

Chassis CSS respects user accessibility preferences by automatically disabling animations when the prefers-reduced-motion media query is detected. See the reduced motion guidelines in our accessibility documentation for implementation details.

Implementation

Before implementing offcanvas panels, note these important considerations:

  • Offcanvas shares JavaScript functionality with modals but operates as a separate plugin
  • When shown, offcanvas includes a default backdrop that can be clicked to hide the panel
  • Only one offcanvas can be displayed at a time by default
  • Body scrolling is disabled when an offcanvas is visible unless configured otherwise
  • Use margin or translate on wrapper elements instead of the .offcanvas element directly due to CSS animation handling

Examples

Explore these practical examples to see Chassis CSS offcanvas in action across different use cases and configurations. Each example demonstrates specific features to help you implement offcanvas panels effectively in your projects.

Live demo

Use the buttons below to show and hide an offcanvas element via JavaScript that toggles the .show class. You can trigger offcanvas with both links using href or buttons using data-cx-target.

Link with href
Offcanvas
Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.
html
<a class="button primary" data-cx-toggle="offcanvas" href="#offcanvasExample" role="button" aria-controls="offcanvasExample">
  Link with href
</a>
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasExample" aria-controls="offcanvasExample">
  Button with data-cx-target
</button>

<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasExampleLabel">Offcanvas</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-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="dropdown mt-medium">
      <button class="button secondary dropdown-toggle" type="button" data-cx-toggle="dropdown">
        Dropdown button
      </button>
      <ul class="dropdown-menu">
        <li><a class="dropdown-item" href="#">Action</a></li>
        <li><a class="dropdown-item" href="#">Another action</a></li>
        <li><a class="dropdown-item" href="#">Something else here</a></li>
      </ul>
    </div>
  </div>
</div>

Body scrolling options

Control how the page body behaves when an offcanvas is visible. By default, body scrolling is disabled to focus attention on the offcanvas content.

Enable body scrolling

Use the data-cx-scroll="true" attribute to allow the body to scroll while the offcanvas is open. This is useful for reference panels or filters where users might need to scroll the main content.

Offcanvas with body scrolling

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

html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasScrolling" aria-controls="offcanvasScrolling">Enable body scrolling</button>

<div class="offcanvas offcanvas-start" data-cx-scroll="true" data-cx-backdrop="false" tabindex="-1" id="offcanvasScrolling" aria-labelledby="offcanvasScrollingLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasScrollingLabel">Offcanvas with body scrolling</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" 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>
</div>

Body scrolling with backdrop

You can also enable body scrolling while maintaining a visible backdrop for better visual separation.

Backdrop with scrolling

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

html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasWithBothOptions" aria-controls="offcanvasWithBothOptions">Enable both scrolling & backdrop</button>

<div class="offcanvas offcanvas-start" data-cx-scroll="true" tabindex="-1" id="offcanvasWithBothOptions" aria-labelledby="offcanvasWithBothOptionsLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasWithBothOptionsLabel">Backdrop with scrolling</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" 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>
</div>

Static backdrop

When backdrop is set to static, the offcanvas will not close when clicking outside of it, ensuring users must explicitly dismiss the panel.

Offcanvas
I will not close if you click outside of me.
html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#staticBackdrop" aria-controls="staticBackdrop">
  Toggle static offcanvas
</button>

<div class="offcanvas offcanvas-start" data-cx-backdrop="static" tabindex="-1" id="staticBackdrop" aria-labelledby="staticBackdropLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="staticBackdropLabel">Offcanvas</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    <div>
      I will not close if you click outside of me.
    </div>
  </div>
</div>

Customization options

Tailor offcanvas panels to your specific design and functional requirements with these customization options. Chassis CSS provides comprehensive control over positioning, responsive behavior, and visual presentation.

Placement options

Offcanvas panels can slide in from any edge of the viewport. Choose the placement that best fits your layout and user experience needs.

PlacementClassDescription
Left.offcanvas-startSlides in from the left edge (default LTR)
Right.offcanvas-endSlides in from the right edge
Top.offcanvas-topSlides down from the top edge
Bottom.offcanvas-bottomSlides up from the bottom edge

Top placement

Offcanvas top
This panel slides down from the top of the viewport.
html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasTop" aria-controls="offcanvasTop">Toggle top offcanvas</button>

<div class="offcanvas offcanvas-top" tabindex="-1" id="offcanvasTop" aria-labelledby="offcanvasTopLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasTopLabel">Offcanvas top</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    This panel slides down from the top of the viewport.
  </div>
</div>

Right placement

Offcanvas right
This panel slides in from the right edge.
html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasRight" aria-controls="offcanvasRight">Toggle right offcanvas</button>

<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasRight" aria-labelledby="offcanvasRightLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasRightLabel">Offcanvas right</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    This panel slides in from the right edge.
  </div>
</div>

Bottom placement

Offcanvas bottom
This panel slides up from the bottom of the viewport.
html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasBottom" aria-controls="offcanvasBottom">Toggle bottom offcanvas</button>

<div class="offcanvas offcanvas-bottom" tabindex="-1" id="offcanvasBottom" aria-labelledby="offcanvasBottomLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasBottomLabel">Offcanvas bottom</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body small">
    This panel slides up from the bottom of the viewport.
  </div>
</div>

Responsive behavior

Responsive offcanvas classes hide content outside the viewport from a specified breakpoint and down. Above that breakpoint, the contents within will behave as usual.

ClassBehavior
.offcanvasAlways behaves as offcanvas
.small:offcanvasOffcanvas below small breakpoint
.medium:offcanvasOffcanvas below medium breakpoint
.large:offcanvasOffcanvas below large breakpoint
.xlarge:offcanvasOffcanvas below xlarge breakpoint
.2xlarge:offcanvasOffcanvas below 2xlarge breakpoint
Resize your browser to show the responsive offcanvas toggle.
Responsive offcanvas

This is content within an .large:offcanvas.

html
<button class="button primary large:d-none" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasResponsive" aria-controls="offcanvasResponsive">Toggle offcanvas</button>

<div class="alert alert-info d-none large:d-block">Resize your browser to show the responsive offcanvas toggle.</div>

<div class="large:offcanvas offcanvas-end" tabindex="-1" id="offcanvasResponsive" aria-labelledby="offcanvasResponsiveLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasResponsiveLabel">Responsive offcanvas</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" data-cx-target="#offcanvasResponsive" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    <p class="mb-0">This is content within an <code>.large:offcanvas</code>.</p>
  </div>
</div>

Accessibility

Since the offcanvas panel is conceptually a modal dialog, be sure to add aria-labelledby="..."—referencing the offcanvas title—to .offcanvas. Note that you don't need to add role="dialog" since we already add it via JavaScript.

CSS

Custom properties

These CSS variables control the component's appearance and can be modified dynamically on the page. Components use cascading variables, allowing seamless variations in size, color, and style without redundant style declarations through component inheritance and the context class system.

--#{$prefix}offcanvas-zindex: #{$zindex-offcanvas};
--#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width};
--#{$prefix}offcanvas-height: #{$offcanvas-vertical-height};
--#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x};
--#{$prefix}offcanvas-padding-y: #{$offcanvas-padding-y};
--#{$prefix}offcanvas-fg-color: #{$offcanvas-fg-color};
--#{$prefix}offcanvas-bg-color: #{$offcanvas-bg-color};
--#{$prefix}offcanvas-border-width: #{$offcanvas-border-width};
--#{$prefix}offcanvas-border-color: #{$offcanvas-border-color};
--#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow};
--#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out};
--#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height};

Sass variables

These Sass variables are also exposed as CSS custom properties using the --cx- prefix. A Sass variable $variable-name becomes available as --cx-variable-name in CSS, allowing for styles to be modified dynamically on the page. See the context components page for more details.

$offcanvas-padding-y:               $modal-window-padding-y;
$offcanvas-padding-x:               $modal-window-padding-x;
$offcanvas-horizontal-width:        25rem; //400px;
$offcanvas-vertical-height:         30vh;
$offcanvas-transition-duration:     .3s;
$offcanvas-border-color:            $modal-window-border-color;
$offcanvas-border-width:            $modal-window-border-width;
$offcanvas-title-line-height:       map-get($modal-title-font, "line-height");
$offcanvas-bg-color:                var(--#{$prefix}bg-main);
$offcanvas-fg-color:                   var(--#{$prefix}fg-main);
$offcanvas-box-shadow:              $modal-window-shadow-xsmall;
$offcanvas-backdrop-color:          $modal-backdrop-color;
$offcanvas-backdrop-opacity:        $modal-backdrop-opacity;

JavaScript

Chassis CSS provides a comprehensive JavaScript API for controlling offcanvas panels programmatically. You can create, show, hide, and configure offcanvas behavior dynamically for complex interactions.

Data attributes

The simplest way to activate an offcanvas is using data attributes:

<!-- Button to trigger the offcanvas -->
<button data-cx-toggle="offcanvas" data-cx-target="#myOffcanvas">Open panel</button>

<!-- Close button within the offcanvas -->
<button data-cx-dismiss="offcanvas">Close</button>

Initialization

For more control, initialize offcanvas with JavaScript:

// Basic initialization
const myOffcanvas = new chassis.Offcanvas(document.getElementById('myOffcanvas'))

// With a CSS selector
const anotherOffcanvas = new chassis.Offcanvas('#anotherOffcanvas')

// With options
const configuredOffcanvas = new chassis.Offcanvas('#configuredOffcanvas', {
  backdrop: 'static',
  keyboard: false,
  scroll: true
})

Configuration options

Chassis components offer flexible configuration through both data attributes and JavaScript. To use data attributes, prefix any option with data-cx- followed by the option name in kebab-case format (using hyphens instead of camelCase). For example, write data-cx-custom-class="my-class" rather than data-cx-customClass="my-class".

For more complex configurations, Chassis provides the data-cx-config attribute which accepts a JSON string of multiple settings. This approach simplifies markup when configuring several options at once. If the same option appears in both data-cx-config and as a separate data attribute (like data-cx-title), the individual attribute takes precedence. You can also use JSON values in individual attributes, such as data-cx-delay='{"show":100,"hide":200}' for more granular control.

When initializing components, Chassis merges configurations from multiple sources in this priority order: default settings, data-cx-config values, individual data-cx-* attributes, and finally any JavaScript object options. Values defined later in this sequence override earlier ones.

OptionTypeDefaultDescription
backdropboolean, 'static'trueApply a backdrop on body while offcanvas is open. Set to 'static' for a backdrop that doesn't close on click.
keyboardbooleantrueCloses the offcanvas when escape key is pressed.
scrollbooleanfalseAllow body scrolling while offcanvas is open.

Methods

All Chassis CSS component methods are asynchronous and initiate CSS transitions. Methods return immediately when the transition begins, not when it completes. Calling methods on components that are already transitioning will be ignored to prevent conflicts. Learn more about Chassis JavaScript patterns.

MethodDescription
show()Shows an offcanvas element. Returns before animation completes.
hide()Hides an offcanvas element. Returns before animation completes.
toggle()Toggles an offcanvas element to shown or hidden.
dispose()Destroys an element's offcanvas functionality.
getInstance()Static method to get the offcanvas instance associated with an element.
getOrCreateInstance()Static method to get existing offcanvas instance or create a new one.

Usage example:

// Initialize with options
const offcanvas = new chassis.Offcanvas('#myOffcanvas', {
  keyboard: false
})

// Show the offcanvas programmatically
document.getElementById('showButton').addEventListener('click', () => {
  offcanvas.show()
})

// Hide after a user action
document.getElementById('completeAction').addEventListener('click', () => {
  // Perform action, then hide offcanvas
  saveData().then(() => offcanvas.hide())
})

Events

Chassis CSS provides events to hook into offcanvas behavior:

EventDescription
show.cx.offcanvasFires immediately when the show method is called.
shown.cx.offcanvasFires when an offcanvas element has been made visible (after animations).
hide.cx.offcanvasFires immediately when the hide method is called.
hidden.cx.offcanvasFires when an offcanvas element has been hidden (after animations).
hidePrevented.cx.offcanvasFires when offcanvas hiding is prevented (static backdrop click or keyboard disabled with escape key).

Event handling example:

const offcanvasElement = document.getElementById('navigationOffcanvas')

// Do something when offcanvas is about to show
offcanvasElement.addEventListener('show.cx.offcanvas', event => {
  // Update navigation based on current state
  updateNavigation()
})

// Do something when offcanvas is fully shown
offcanvasElement.addEventListener('shown.cx.offcanvas', () => {
  // Focus the first navigation item
  document.getElementById('firstNavItem').focus()
})

// Clean up when offcanvas is hidden
offcanvasElement.addEventListener('hidden.cx.offcanvas', () => {
  // Reset any temporary states
  resetTemporaryStates()
})

Examples

Offcanvas components

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

Offcanvas
Content for the offcanvas goes here. You can place just about any Chassis CSS component or custom elements here.
html
<div class="offcanvas offcanvas-start show" tabindex="-1" id="offcanvas" aria-labelledby="offcanvasLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasLabel">Offcanvas</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    Content for the offcanvas goes here. You can place just about any Chassis CSS component or custom elements here.
  </div>
</div>

Live demo

Use the buttons below to show and hide an offcanvas element via JavaScript that toggles the .show class on an element with the .offcanvas class.

  • .offcanvas hides content (default)
  • .offcanvas.show shows content

You can use a link with the href attribute, or a button with the data-cx-target attribute. In both cases, the data-cx-toggle="offcanvas" is required.

Link with href
Offcanvas
Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.
html
<a class="button primary" data-cx-toggle="offcanvas" href="#offcanvasExample" role="button" aria-controls="offcanvasExample">
  Link with href
</a>
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasExample" aria-controls="offcanvasExample">
  Button with data-cx-target
</button>

<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasExampleLabel">Offcanvas</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-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="dropdown mt-medium">
      <button class="button secondary dropdown-toggle" type="button" data-cx-toggle="dropdown">
        Dropdown button
      </button>
      <ul class="dropdown-menu">
        <li><a class="dropdown-item" href="#">Action</a></li>
        <li><a class="dropdown-item" href="#">Another action</a></li>
        <li><a class="dropdown-item" href="#">Something else here</a></li>
      </ul>
    </div>
  </div>
</div>

Body scrolling

Scrolling the <body> element is disabled when an offcanvas and its backdrop are visible. Use the data-cx-scroll attribute to enable <body> scrolling.

Offcanvas with body scrolling

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

html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasScrolling" aria-controls="offcanvasScrolling">Enable body scrolling</button>

<div class="offcanvas offcanvas-start" data-cx-scroll="true" data-cx-backdrop="false" tabindex="-1" id="offcanvasScrolling" aria-labelledby="offcanvasScrollingLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasScrollingLabel">Offcanvas with body scrolling</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" 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>
</div>

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="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasWithBothOptions" aria-controls="offcanvasWithBothOptions">Enable both scrolling & backdrop</button>

<div class="offcanvas offcanvas-start" data-cx-scroll="true" tabindex="-1" id="offcanvasWithBothOptions" aria-labelledby="offcanvasWithBothOptionsLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasWithBothOptionsLabel">Backdrop with scrolling</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" 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>
</div>

Static backdrop

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

Offcanvas
I will not close if you click outside of me.
html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#staticBackdrop" aria-controls="staticBackdrop">
  Toggle static offcanvas
</button>

<div class="offcanvas offcanvas-start" data-cx-backdrop="static" tabindex="-1" id="staticBackdrop" aria-labelledby="staticBackdropLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="staticBackdropLabel">Offcanvas</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    <div>
      I will not close if you click outside of me.
    </div>
  </div>
</div>

Responsive

Added in v5.2.0

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

  • .offcanvas
  • .small:offcanvas
  • .medium:offcanvas
  • .large:offcanvas
  • .xlarge:offcanvas
  • .2xlarge:offcanvas

To make a responsive offcanvas, replace the .offcanvas base class with a responsive variant and ensure your close button has an explicit data-cx-target.

Resize your browser to show the responsive offcanvas toggle.
Responsive offcanvas

This is content within an .large:offcanvas.

html
<button class="button primary large:d-none" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasResponsive" aria-controls="offcanvasResponsive">Toggle offcanvas</button>

<div class="alert alert-info d-none large:d-block">Resize your browser to show the responsive offcanvas toggle.</div>

<div class="large:offcanvas offcanvas-end" tabindex="-1" id="offcanvasResponsive" aria-labelledby="offcanvasResponsiveLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasResponsiveLabel">Responsive offcanvas</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" data-cx-target="#offcanvasResponsive" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    <p class="mb-0">This is content within an <code>.large:offcanvas</code>.</p>
  </div>
</div>

Placement

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

  • .offcanvas-start places offcanvas on the left of the viewport (shown above)
  • .offcanvas-end places offcanvas on the right of the viewport
  • .offcanvas-top places offcanvas on the top of the viewport
  • .offcanvas-bottom places offcanvas on the bottom of the viewport

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

Offcanvas top
...
html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasTop" aria-controls="offcanvasTop">Toggle top offcanvas</button>

<div class="offcanvas offcanvas-top" tabindex="-1" id="offcanvasTop" aria-labelledby="offcanvasTopLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasTopLabel">Offcanvas top</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    ...
  </div>
</div>
Offcanvas right
...
html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasRight" aria-controls="offcanvasRight">Toggle right offcanvas</button>

<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasRight" aria-labelledby="offcanvasRightLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasRightLabel">Offcanvas right</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body">
    ...
  </div>
</div>
Offcanvas bottom
...
html
<button class="button primary" type="button" data-cx-toggle="offcanvas" data-cx-target="#offcanvasBottom" aria-controls="offcanvasBottom">Toggle bottom offcanvas</button>

<div class="offcanvas offcanvas-bottom" tabindex="-1" id="offcanvasBottom" aria-labelledby="offcanvasBottomLabel">
  <div class="offcanvas-header">
    <h5 class="offcanvas-title" id="offcanvasBottomLabel">Offcanvas bottom</h5>
    <button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Close"></button>
  </div>
  <div class="offcanvas-body small">
    ...
  </div>
</div>

Accessibility

Since the offcanvas panel is conceptually a modal dialog, be sure to add aria-labelledby="..."—referencing the offcanvas title—to .offcanvas. Note that you don’t need to add role="dialog" since we already add it via JavaScript.

CSS

This component can be customized using CSS variables, allowing for styles to be modified dynamically on the page. These CSS variables are part of Chassis CSS's design token system, giving design teams control over component appearance. See the design tokens page for more details.

Custom properties

These CSS variables control the component's appearance and can be modified dynamically on the page. Components use cascading variables, allowing seamless variations in size, color, and style without redundant style declarations through component inheritance and the context class system.

--#{$prefix}offcanvas-zindex: #{$zindex-offcanvas};
--#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width};
--#{$prefix}offcanvas-height: #{$offcanvas-vertical-height};
--#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x};
--#{$prefix}offcanvas-padding-y: #{$offcanvas-padding-y};
--#{$prefix}offcanvas-fg-color: #{$offcanvas-fg-color};
--#{$prefix}offcanvas-bg-color: #{$offcanvas-bg-color};
--#{$prefix}offcanvas-border-width: #{$offcanvas-border-width};
--#{$prefix}offcanvas-border-color: #{$offcanvas-border-color};
--#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow};
--#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out};
--#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height};

Sass variables

These Sass variables are also exposed as CSS custom properties using the --cx- prefix. A Sass variable $variable-name becomes available as --cx-variable-name in CSS, allowing for styles to be modified dynamically on the page. See the context components page for more details.

$offcanvas-padding-y:               $modal-window-padding-y;
$offcanvas-padding-x:               $modal-window-padding-x;
$offcanvas-horizontal-width:        25rem; //400px;
$offcanvas-vertical-height:         30vh;
$offcanvas-transition-duration:     .3s;
$offcanvas-border-color:            $modal-window-border-color;
$offcanvas-border-width:            $modal-window-border-width;
$offcanvas-title-line-height:       map-get($modal-title-font, "line-height");
$offcanvas-bg-color:                var(--#{$prefix}bg-main);
$offcanvas-fg-color:                   var(--#{$prefix}fg-main);
$offcanvas-box-shadow:              $modal-window-shadow-xsmall;
$offcanvas-backdrop-color:          $modal-backdrop-color;
$offcanvas-backdrop-opacity:        $modal-backdrop-opacity;

Javascript

The offcanvas plugin utilizes a few classes and attributes to handle the heavy lifting:

  • .offcanvas hides the content
  • .offcanvas.show shows the content
  • .offcanvas-start hides the offcanvas on the left
  • .offcanvas-end hides the offcanvas on the right
  • .offcanvas-top hides the offcanvas on the top
  • .offcanvas-bottom hides the offcanvas on the bottom

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

Data attributes

You can use data attributes to control offcanvas behavior without writing JavaScript. The following attributes are available:

Toggle

Add data-cx-toggle="offcanvas" and a data-cx-target or href to the element to automatically assign control of one offcanvas element. The data-cx-target attribute accepts a CSS selector to apply the offcanvas to. Be sure to add the class offcanvas to the offcanvas element. If you’d like it to default open, add the additional class show.

Dismiss

Enable dismissal with the data-cx-dismiss attribute on a button within the offcanvas:

<button type="button" class="close-button" data-cx-dismiss="offcanvas" aria-label="Dismiss"></button>

Or on a button outside the offcanvas using the additional data-cx-target attribute:

<button type="button" class="close-button" data-cx-dismiss="offcanvas" data-cx-target="#my-offcanvas" aria-label="Dismiss offcanvas"></button>
When a offcanvas is dismissed, it is completely removed from the DOM. If you need to maintain focus management for accessibility, listen for the closed.cx.offcanvas event to set focus to an appropriate element.

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

Initialization

Enable manually with:

const offcanvasElementList = document.querySelectorAll('.offcanvas')
const offcanvasList = [...offcanvasElementList].map(offcanvasEl => new chassis.Offcanvas(offcanvasEl))

Options

Chassis components offer flexible configuration through both data attributes and JavaScript. To use data attributes, prefix any option with data-cx- followed by the option name in kebab-case format (using hyphens instead of camelCase). For example, write data-cx-custom-class="my-class" rather than data-cx-customClass="my-class".

For more complex configurations, Chassis provides the data-cx-config attribute which accepts a JSON string of multiple settings. This approach simplifies markup when configuring several options at once. If the same option appears in both data-cx-config and as a separate data attribute (like data-cx-title), the individual attribute takes precedence. You can also use JSON values in individual attributes, such as data-cx-delay='{"show":100,"hide":200}' for more granular control.

When initializing components, Chassis merges configurations from multiple sources in this priority order: default settings, data-cx-config values, individual data-cx-* attributes, and finally any JavaScript object options. Values defined later in this sequence override earlier ones.

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

Methods

All Chassis CSS component methods are asynchronous and initiate CSS transitions. Methods return immediately when the transition begins, not when it completes. Calling methods on components that are already transitioning will be ignored to prevent conflicts. Learn more about Chassis JavaScript patterns.

Activates your content as an offcanvas element. Accepts an optional options object.

You can create an offcanvas instance with the constructor, for example:

const cxOffcanvas = new chassis.Offcanvas('#myOffcanvas')
MethodDescription
disposeDestroys an element’s offcanvas.
getInstanceStatic method which allows you to get the offcanvas instance associated with a DOM element.
getOrCreateInstanceStatic method which allows you to get the offcanvas instance associated with a DOM element, or create a new one in case it wasn’t initialized.
hideHides an offcanvas element. Returns to the caller before the offcanvas element has actually been hidden (i.e. before the hidden.cx.offcanvas event occurs).
showShows an offcanvas element. Returns to the caller before the offcanvas element has actually been shown (i.e. before the shown.cx.offcanvas event occurs).
toggleToggles an offcanvas element to shown or hidden. Returns to the caller before the offcanvas element has actually been shown or hidden (i.e. before the shown.cx.offcanvas or hidden.cx.offcanvas event occurs).

Events

Chassis CSS’s offcanvas class exposes a few events for hooking into offcanvas functionality.

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