@components-1812/offcanvas
v0.0.3
Published
A web component for custom offcanvas, lateral panel
Maintainers
Readme
Offcanvas custom element

Examples
Codepen:
Overview2 - Panel placement3 - Panel scroll4 - Custom icons5 - Backdrop content6 - Backdrop static7 - Panel responsive
Installation
NPM
npm install @components-1812/offcanvasCDN
Load the component bundle directly from a CDN — this will automatically register the element and inject styles:
<!-- Classic script -->
<script src="https://cdn.jsdelivr.net/npm/@components-1812/[email protected]/dist/index.min.js"></script>
<!-- ES module -->
<script type="module">
import "https://cdn.jsdelivr.net/npm/@components-1812/[email protected]/dist/index.min.js";
</script>Alternatively, you can manually import, load the styles, and define the element yourself:
<script type="module">
import Offcanvas from "https://cdn.jsdelivr.net/npm/@components-1812/[email protected]/src/Offcanvas.min.js";
// Load the stylesheet from a CDN
Offcanvas.stylesSheets.links.push(
"https://cdn.jsdelivr.net/npm/@components-1812/[email protected]/src/Offcanvas.min.css"
);
//Define with the default tag
Offcanvas.define();
</script>jsdelivr:
Offcanvas packageOffcanvas.jsOffcanvas.cssOffcanvas.min.jsOffcanvas.min.cssBundleunpkg:
Offcanvas packageOffcanvas.jsOffcanvas.cssOffcanvas.min.jsOffcanvas.min.cssBundle
Usage
Vite Ecosystem
If you are using Vite or a Vite-based framework such as Astro, you can import the component in a client-side script:
import '@components-1812/offcanvas';and use it in your HTML:
<custom-offcanvas open variant="right global" handle-button>
<!-- Panel content -->
<div slot="header">Header</div>
<div>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod.</p>
</div>
<div slot="footer">Footer</div>
<!--Custom icons -->
<div slot="close-button">❌</div>
<div slot="handle-button" data-rotate-icon>➡️</div>
<!-- Backdrop content -->
<div slot="backdrop" style="position: absolute; top: 0; left: 0;">
<p>This is the backdrop content.</p>
<p>You can add any content here.</p>
</div>
</custom-offcanvas>Other Frameworks
If you are using a builder or framework that does not support importing with ?raw,
you can load and register the component using the bundle version in dist/index.min.js, which includes all CSS injected via CSS-in-JS and AdoptedStyleSheets:
import '@components-1812/offcanvas/dist/index.min.js';For customizing the component definition or manually loading the stylesheets, see [Defining and Adding Stylesheets Manually](#Defining and Adding Stylesheets Manually).
Node
The
distfolder includes minified versions:Offcanvas.min.cssandOffcanvas.min.js, which can be used anywhere.
Defining and Adding Stylesheets Manually
If you want to add custom stylesheets to the component or need to load stylesheets from a different path, you can do it like this:
AdoptedStyleSheets (recommended)
Using your builder’s import raw method,
CSSStyleSheet, and the component’sAdoptedStyleSheetsproperty:import Offcanvas from "@components-1812/offcanvas/Offcanvas.js"; import OffcanvasRawCSS from "@components-1812/offcanvas/Offcanvas.css?raw"; //Create a CSSStyleSheet and add it to the component const OffcanvasCSS = new CSSStyleSheet(); OffcanvasCSS.replaceSync(OffcanvasRawCSS); Offcanvas.stylesSheets.adopted.push(OffcanvasCSS); //Define the component with default tag name Offcanvas.define();Raw CSS in a
<style>tagUsing a
<style>tag inside the shadow root of the component:import Offcanvas from "@components-1812/offcanvas/Offcanvas.js"; //Add the raw stylesheet to the component const OffcanvasRawCSS = `:host { /* ...Offcanvas.css styles... */ }`; Offcanvas.stylesSheets.raw.push(OffcanvasRawCSS); //Define the component custom tag name Offcanvas.define('other-custom-tag-name');External CSS files in a
<link>tagUsing a
<link>tag inside the shadow root of the component:import Offcanvas from "@components-1812/offcanvas/Offcanvas.js"; //Add the url source stylesheets to the component Offcanvas.stylesSheets.links.push('https://cdn.example.com/Offcanvas.css'); //Define the component manually customElements.define('custom-offcanvas', Offcanvas);
Customization: CSS Variables
--offcanvas-position: absolute;
--offcanvas-z-index: 8010;
/* Panel */
--offcanvas-panel-width: 300px;
--offcanvas-panel-height: 100%;
--offcanvas-panel-padding: 5px;
--offcanvas-panel-transition: margin 0.3s ease-in-out;
--offcanvas-panel-header-padding: 5px;
--offcanvas-panel-body-padding: 5px;
--offcanvas-panel-footer-padding: 5px;
--offcanvas-shadow: 0 1px 3px 0 #3c40434d, 0 4px 8px 3px #3c404326;
--offcanvas-panel-bg: #222;
--offcanvas-panel-color: #fff;
--offcanvas-panel-header-bg: var(--offcanvas-panel-bg);
--offcanvas-panel-header-color: var(--offcanvas-panel-color);
--offcanvas-panel-footer-bg: var(--offcanvas-panel-bg);
--offcanvas-panel-footer-color: var(--offcanvas-panel-color);
--offcanvas-panel-border-width: 1px;
--offcanvas-panel-border-style: solid;
--offcanvas-panel-border-color: #ccc;
--offcanvas-panel-border: var(--offcanvas-panel-border-width) var(--offcanvas-panel-border-style) var(--offcanvas-panel-border-color);
--offcanvas-panel-border-radius: 0px;
/* Backdrop */
--offcanvas-backdrop-bg: #00000080;
--offcanvas-backdrop-color: #fff;
--offcanvas-backdrop-transition: background-color 0.3s ease-in-out;
/* Close button */
--offcanvas-close-button-width: 40px;
--offcanvas-close-button-height: 40px;
--offcanvas-close-button-padding: 10px;
--offcanvas-close-button-bg: transparent;
--offcanvas-close-button-color: #fff;
--offcanvas-close-button-border: none;
--offcanvas-close-button-font-size: 1.5rem;
--offcanvas-close-button-cursor: pointer;
/* Handle button */
--offcanvas-handle-button-width: 50px;
--offcanvas-handle-button-height: 100px;
--offcanvas-handle-button-padding: 5px;
--offcanvas-handle-button-bg: #444;
--offcanvas-handle-button-color: #fff;
--offcanvas-handle-button-border: none;
--offcanvas-handle-button-border-radius: 10px;
--offcanvas-handle-button-cursor: pointer;
--offcanvas-handle-button-font-size: 1rem;
--offcanvas-handle-button-shadow: var(--offcanvas-shadow);Top and Bottom Offcanvas
--offcanvas-panel-width: 100%;
--offcanvas-panel-height: 300px;
--offcanvas-handle-button-width: 100px;
--offcanvas-handle-button-height: 50px;
--offcanvas-panel-shadow: 1px 0 3px 0 #3c40434d, 4px 0 8px 3px #3c404326;Responsive Panel
For responsive design, there will be times when you want the panel to occupy the full width of the screen, especially on mobile devices.
You can achieve this by adding a CSS media query like the following:
custom-offcanvas {
@media (width <= 500px) {
--offcanvas-panel-width: 100%;
}
}This will ensure that the offcanvas panel expands to the full screen width on devices with a width of 500px or less.
See the example: 7 - Panel responsive
Open and close
You can open the offcanvas panel using the open attribute:
<custom-offcanvas open></custom-offcanvas>Via JavaScript, you can use the open property (mirrored attribute):
const offcanvas = document.querySelector('custom-offcanvas');
// Open the panel
offcanvas.open = true;
// Close the panel
offcanvas.open = false;You can also control the panel with the methods: .show(), .hide(), .toggle()
const offcanvas = document.querySelector('custom-offcanvas');
// Show the panel
offcanvas.show();
// Hide the panel
offcanvas.hide();
// Toggle the panel (switch state)
offcanvas.toggle(); // toggle current state
offcanvas.toggle(true); // force open
offcanvas.toggle(false); // force closeSlots
The default slot is reserved for the panel body, which contains the main content.
You can also use the following named slots:
slot="header"– for the panel header.slot="footer"– for the panel footer.
<custom-offcanvas open variant="right" handle-button>
<div slot="header">Header</div>
<div>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam, quod.</p>
</div>
<div slot="footer">Footer</div>
</custom-offcanvas>Customizing Buttons
You can replace the default icons for the close button and the handle button (if present) using:
slot="close-button"slot="handle-button"
para modificar los iconos por defecto del close button y el handle button (si esta) puedes usar slot="close-button" y slot="handle-button"
<custom-offcanvas open variant="right" handle-button>
<div slot="close-button">❌</div>
<div slot="handle-button" data-rotate-icon>➡️</div>
</custom-offcanvas>Note
For the handle button, you can add the attribute
data-rotate-iconso that the icon always rotates to point in the correct direction according to the panel position and open/closed state.To work correctly, the icon must initially point to the right.
Backdrop
The backdrop slot allows you to add custom content positioned around the panel for richer interactions or decorations.
Elements in this slot should use position: absolute;
Since the backdrop changes size when the panel opens or closes, the elements will move together with the panel.
<custom-offcanvas open variant="left" handle-button>
<!-- Backdrop content -->
<div slot="backdrop" style="position: absolute; top: 0; left: 0;">
<p>This is the backdrop content.</p>
<p>You can add any content here.</p>
</div>
<div slot="backdrop" style="position: absolute; bottom: 0; right: 0;">
<p>This is another backdrop content.</p>
<p>You can customize the backdrop as needed.</p>
</div>
</custom-offcanvas>You can also control the visibility of backdrop elements based on the panel state using attributes like:
data-hide-when-closed– hides the element when the panel is closed.data-hide-when-opened– hides the element when the panel is open.
<custom-offcanvas open variant="left" handle-button>
<!-- Backdrop content -->
<div slot="backdrop" style="position: absolute; top: 0; right: 0;" data-hide-when-closed>
<p>This content will hide when the offcanvas is closed.</p>
</div>
<div slot="backdrop" style="position: absolute; bottom: 0; left: 0;" data-hide-when-opened>
<p>This content will hide when the offcanvas is opened.</p>
</div>
</custom-offcanvas>See the example: 5 - Backdrop content
Variants
Panel Global and Local Positioning
You can control whether the offcanvas panel is positioned relative to the viewport or inside its container using the variant attribute:
local(default) – The panel is positionedabsoluterelative to its nearest positioned ancestor.global– The panel is positionedfixedrelative to the viewport. This is useful for modals or overlays.
<!-- Fixed to the viewport -->
<custom-offcanvas variant="top global"></custom-offcanvas>
<!-- Positioned inside a container -->
<div class="container" style="position: relative;">
<custom-offcanvas variant="left local"></custom-offcanvas>
</div>Panel Placement
The variant attribute defines the position of the offcanvas panel: left, right, top, bottom
<custom-offcanvas variant="left"></custom-offcanvas>
<custom-offcanvas variant="right"></custom-offcanvas>
<custom-offcanvas variant="top"></custom-offcanvas>
<custom-offcanvas variant="bottom"></custom-offcanvas>See the example: 2 - Panel placement
Panel Scroll
By default, the panel does not scroll. You can customize the scroll behavior using the following variants:
scroll-full: The entire panel content scrolls.scroll-inner: All content scrolls except the headerscroll-body: Only the body scrolls; header and footer remain fixed.
<custom-offcanvas variant="scroll-full"></custom-offcanvas>
<custom-offcanvas variant="scroll-inner"></custom-offcanvas>
<custom-offcanvas variant="scroll-body"></custom-offcanvas>See the example: 3 - Panel scroll
Handle button
By default, the component does not provide any control to open the panel; you must add it manually.
With the handle-button attribute, the component automatically adds a button inside the backdrop content, centered along the edge of the panel. This button allows users to open and close the panel.
<custom-offcanvas variant="right" handle-button></custom-offcanvas>Static and Transparent Backdrop
backdrop-static: By default, clicking on the backdrop closes the panel.You can disable this behavior by adding the backdrop-static variant:
<custom-offcanvas variant="backdrop-static"></custom-offcanvas>With this
variant, clicking on the backdrop won’t close the panel, and the page behind it remains interactive while the panel is open.backdrop-transparentIf you want to hide the backdrop background when the panel is open, you have two options:
- Override the CSS variable:
--offcanvas-backdrop-bg - Or, more easily, use the
backdrop-transparentvariant:
<custom-offcanvas variant="backdrop-transparent"></custom-offcanvas>- Override the CSS variable:
API
Attributes
variant: Panel position or visual style.- Panel position:
left,top,right,bottom - Panel scroll:
scroll-full,scroll-inner,scroll-body - Page position:
global,local
- Panel position:
open(boolean, default false): Whether the panel is open.handle-button(boolean, default false): Whether to show a floating handle button.
Properties
Mirrored
variant(string): Panel position or visual style.open(boolean): Whether the panel is open.handleButton(boolean): Whether the handle button is visible.
Methods
show(): Opens the panel (open = true).
hide(): Closes the panel (open = false).
toggle(force?: boolean): Toggles the panel. If force is true or false, sets the panel state accordingly.
Events
ready-links: Fired when all external stylesheet links have finished loading. Provides a detail with the results of each stylesheet.ready: Dispatched when the component has finished initializing (end of connectedCallback)
Static properties
VERSION(string): Component version (0.0.3).DEFAULT_TAG_NAME(string): Default tag name (custom-offcanvas) use it to define the custom element inindex.jsanddefine.jsDEFAULT_ICONS(object): Default svg icons forclose-buttonandhandle-button.Offcanvas.DEFAULT_ICONS = { 'close-button': `<svg>...</svg>`, 'handle-button': `<svg data-rotate-icon>...</svg>` }stylesSheets(object): Containslinks,adopted, andrawstylesheets to apply to the component.Offcanvas.stylesSheets = { links: [],//string url css source adopted: [],//CSSStyleSheet instances raw: [],//string raw css };define(tagName?, stylesSheets?)(function): Defines the custom element and optionally adds stylesheets if the element is not already registered.Offcanvas.define('custom-offcanvas', { links: ['https://cdn.example.com/Offcanvas.css'], adopted: [new CSSStyleSheet()], raw: [':host { /* ...Offcanvas.css styles... */ }'], });Internally, this method calls
window.customElements.define(tagName, Offcanvas)
Slots
default: Main content of the panelheader: Header content of the panelfooter: Footer content of the panelclose-button: Icon or content for the close button in the header of the panelhandle-button: Icon or content for the handle button if addedbackdrop: Content inside the backdrop (around the panel)
License
This package is distributed under the MIT license.
Credits
Default icons used in this package are sourced from the Bootstrap Icons project, licensed under the MIT license.
© 2019–2024 The Bootstrap Authors
