@htmlbricks/hb-offcanvas
v0.76.5
Published
Slide-in panel that hosts hb-sidebar-desktop navigation, with Bulma `modal-background` as optional backdrop when `type` is autohide. Can start open or closed; dispatches page changes and open/close state.
Readme
hb-offcanvas — integrator guide
Category: layout · Tags: layout, navigation · Package: @htmlbricks/hb-offcanvas
Summary
hb-offcanvas is a fixed, slide-in drawer on the start edge of the viewport that embeds hb-sidebar-desktop for branded navigation, page selection, optional theme switching, and optional language switching. When type is autohide, a full-viewport Bulma modal-background layer sits under the panel; clicking the dimmed area closes the drawer. The host raises custom events when the drawer opens or closes, when the active page changes, and when the nested sidebar changes language or theme.
The package depends on hb-sidebar-desktop (which in turn uses hb-sidenav-link). Navigation items use the same JSON shape as the sidebar, including optional Bootstrap Icons glyph names on each link.
Behavior
typeautohide(default): Renders the backdrop while the drawer is open. Clicking the backdrop calls the internal close path and dispatchesoffcanvasswitchwithisOpen: false.open: After the host’s reactive setup runs, the drawer is treated as always open (theopenedattribute is forced to an open state for display).small: No backdrop; open state followsopenedlike a non-openmode. Use when you want a sliding panel without modal dismissal (same stacking and panel animation as other modes, without the overlay).
opened: Initial and runtime open state for modes that are nottype="open". In HTML, use string booleansyes/noas for other web components in this library. The implementation treats a truthyopenedthat is not the stringnoas open.Page changes: Choosing a nav entry inside
hb-sidebar-desktopruns the sidebar’s page handler; the host re-dispatchespageChangewith{ page: string }and closes the drawer viaOpenSwitch(false)(so the drawer does not stay open after navigation in the default wiring).groups: May be a parsed JSON string in the effect; invalid JSON is ignored and leaves the previous value.
Styling (Bulma and host tokens)
The shadow tree uses Bulma-derived tokens for the panel fill, shadow, and (when autohide) backdrop color. Stacking and drawer width are controlled on :host so the drawer can sit above siblings such as a mobile layout shell. See Bulma CSS variables and extra/docs.ts for metadata.
| Variable | Purpose |
|----------|---------|
| --hb-offcanvas-host-z | Host stacking context so fixed panel and backdrop paint above following light-DOM siblings (default 1038). |
| --hb-offcanvas-panel-z | Drawer layer above the backdrop (default 1045). |
| --hb-offcanvas-backdrop-z | Backdrop layer (default 1040). |
| --hb-offcanvas-panel-width | Drawer width, capped by the viewport (default 240px). |
| --bulma-scheme-main | Panel background. |
| --bulma-shadow | Elevation shadow on the open drawer. |
| --bulma-modal-background-background-color | Backdrop tint when type is autohide. |
The component also loads Bootstrap Icons from jsDelivr for icon font classes used by nested navigation.
CSS parts
None on hb-offcanvas. hb-sidebar-desktop defines its own parts (for example the header row); see the sidebar README for ::part names.
HTML slots
| Slot | Purpose |
|------|---------|
| test | Optional content at the host root inside #webcomponent, before the panel (for advanced integrations). Main navigation UI lives inside the nested hb-sidebar-desktop, not in this slot. |
Custom element tag
<hb-offcanvas …></hb-offcanvas>Attributes (snake_case; string values in HTML)
Reflectable props follow the usual conventions: booleans as yes / no, objects and arrays as JSON strings, numbers as decimal strings where applicable.
| Attribute | Required | Description |
|-----------|----------|-------------|
| id | No | Optional element id. |
| style | No | Optional inline host styles. |
| type | No | autohide | open | small — backdrop and forced-open behavior (see above). Default in implementation: autohide. |
| opened | No | yes / no — whether the drawer is open (ignored for forced-open when type is open). |
| navlinks | No | JSON string — INavLink[]: key, label, optional icon (Bootstrap Icons name), group, badge, subLinks, etc. Same contract as hb-sidebar-desktop. |
| navpage | No | Active page key string. |
| groups | No | JSON string — { key: string; label: string }[] for section labels in the sidebar. |
| companylogouri | No | Logo image URI for the sidebar header. |
| companytitle | No | Company or product title next to the logo. |
| enablefooter | No | yes / no / false (same contract as hb-sidebar-desktop). Forwarded to the nested sidebar; omitted or truthy values keep the sidebar footer enabled (yes). |
| enablethemeswitch | No | yes / no — passed through to hb-sidebar-desktop (defaults to yes when unset). |
| themepreference | No | light | dark | auto — optional controlled theme for the nested sidebar. |
| i18nlang | No | Language code for the nested sidebar. |
| i18nlanguages | No | JSON string or structured options — { code: string; label: string }[] for the language picker. |
Events
| Event | Detail |
|-------|--------|
| offcanvasswitch | { isOpen: boolean } — emitted when the drawer opens or closes (including initial open when type is open or opened is truthy, and when the backdrop closes the drawer). |
| pageChange | { page: string } — forwarded from hb-sidebar-desktop when the user selects a page; the offcanvas also closes after dispatching. |
| languageChange | { code: string } — bubbled from the nested sidebar’s language control. |
| themeChange | { mode: ThemePreference } where ThemePreference is "light" | "dark" | "auto" — bubbled from the nested sidebar’s theme control. |
Usage notes
- Icons: Use Bootstrap Icons names only (for example
house-door), not class strings — same rule ashb-sidebar-desktop. - Layering: If the drawer or backdrop appears under a sibling layout, raise
--hb-offcanvas-host-z(and panel/backdrop z-tokens if needed) on the host. - Examples: Storybook-style
examplesinextra/docs.tscover default, closed, autohide, and grouped navigation with footer metadata on the data model.
TypeScript typings (authoring)
From types/webcomponent.type.d.ts:
import type { INavLink } from "../../sidenav-link/types/webcomponent.type";
import type {
I18nLanguageOption,
ThemePreference,
} from "../../sidebar-desktop/types/webcomponent.type";
export type Component = {
id?: string;
style?: string;
opened?: boolean;
navlinks?: INavLink[];
navpage?: string;
groups?: { key: string; label: string }[];
companylogouri?: string;
companytitle?: string;
enablefooter?: "yes" | "no" | "false" | null | "" | undefined;
enablethemeswitch?: "yes" | "no" | null | "" | undefined;
themepreference?: ThemePreference | null | "" | undefined;
i18nlang?: string | null | "" | undefined;
i18nlanguages?: I18nLanguageOption[] | string | null | "" | undefined;
type?: "open" | "autohide" | "small";
};
export type Events = {
offcanvasswitch: { isOpen: boolean };
pageChange: { page: string };
languageChange: { code: string };
themeChange: { mode: ThemePreference };
};Minimal HTML
<hb-offcanvas
opened="yes"
type="autohide"
companytitle="Acme"
navpage="home"
navlinks='[{"label":"Home","key":"home","icon":"house-door"}]'
></hb-offcanvas>Listen for open state and navigation:
<script>
const el = document.querySelector("hb-offcanvas");
el.addEventListener("offcanvasswitch", (e) => {
console.log("open:", e.detail.isOpen);
});
el.addEventListener("pageChange", (e) => {
console.log("page:", e.detail.page);
});
</script>