Offcanvas

A panel that slides in from any edge of the viewport for navigation, filters, carts, or secondary content. Composed from OffcanvasHeader, OffcanvasTitle, and OffcanvasBody.

Import

tsx
import {
Offcanvas,
OffcanvasHeader,
OffcanvasTitle,
OffcanvasBody,
} from '@metatoy/bootstrap-styled';

Launch an offcanvas

Like Modal, Offcanvas is controlled — own the show state and pass onHide.

The full controlled pattern:

tsx
import { useState } from 'react';
import { Offcanvas, OffcanvasHeader, OffcanvasTitle, OffcanvasBody, Button, CloseButton } from '@metatoy/bootstrap-styled';

function Example() {
const [show, setShow] = useState(false);
return (
  <>
    <Button variant="secondary" onClick={() => setShow(true)}>Open offcanvas</Button>
    <Offcanvas show={show} onHide={() => setShow(false)} placement="end">
      <OffcanvasHeader>
        <OffcanvasTitle>Offcanvas</OffcanvasTitle>
        <CloseButton onClick={() => setShow(false)} />
      </OffcanvasHeader>
      <OffcanvasBody>Panel content.</OffcanvasBody>
    </Offcanvas>
  </>
);
}

Overlay scope. The open panel renders through a portal, fixed to the viewport edge, with a backdrop over the whole page — that is the real component behavior, not something scoped to this demo card. Escape or a backdrop click dismisses it.

Panel surface

The Offcanvas* parts are plain styled elements, so you can render the panel surface inline (without the slide-in overlay) to preview its structure:

Placements

placement="start" | "end" | "top" | "bottom" chooses the edge the panel enters from. start/end are 400px-wide side panels; top/bottom are 30vh-tall drawers.

Props

PropTypeDefaultDescription
showboolean
onHide() => void
placement"start" | "end" | "top" | "bottom"
childrenReact.ReactNode

The subcomponents — OffcanvasHeader, OffcanvasTitle, OffcanvasBody — are styled elements that accept all native attributes for their tag.

Theming

The panel reads --bs-body-bg / --bs-body-color for its fill and --bs-border-color-translucent for the edge border; the header divider uses --bs-border-color. No box-shadow is applied by default (matching Bootstrap). Because the panel is portaled, the library re-applies the active theme’s variables inside the portal so your token overrides still reach it.

Accessibility

The panel is rendered with aria-modal="true" and a dialog role, and traps focus while open (restoring it to the trigger on close). Provide an OffcanvasTitle and wire a CloseButton to onHide. Escape closes the panel.

Open in Ladle

Offcanvas · Ladle