Drawer

A panel that slides in from the side of the viewport and overlays the page, built on top of the native <dialog> element for its modal behavior.

Examples

Default

Filter results

End-anchored, large

Quick view

A wider drawer for record detail panels.

Basic usage

Preferences

Drawer body content sits here. The body grows to fill remaining vertical space and scrolls when content overflows, so headers and footers stay pinned at the edges.

Drop form fields, navigation links, or any long-form content inside. Native focus trapping handles Tab / Shift+Tab within the drawer.

<brio-drawer>
                <dialog class="drawer" id="demo-drawer-basic">
                    <div class="drawer-panel">
                        <header>
                            <h3>Preferences</h3>
                            <button
                                class="dismiss"
                                type="button"
                                commandfor="demo-drawer-basic"
                                command="--dismiss"
                                aria-label="Close"
                            >
                                &times;
                            </button>
                        </header>
                        <section>
                            <p>
                                Drawer body content sits here. The body grows to fill remaining
                                vertical space and scrolls when content overflows, so headers and
                                footers stay pinned at the edges.
                            </p>
                            <p>
                                Drop form fields, navigation links, or any long-form content inside.
                                Native focus trapping handles Tab / Shift+Tab within the drawer.
                            </p>
                        </section>
                        <footer>
                            <button
                                class="button is-outlined"
                                type="button"
                                commandfor="demo-drawer-basic"
                                command="--dismiss"
                            >
                                Cancel
                            </button>
                            <button
                                class="button"
                                type="button"
                                commandfor="demo-drawer-basic"
                                command="--dismiss"
                            >
                                Save
                            </button>
                        </footer>
                    </div>
                </dialog>
            </brio-drawer>

            <button
                class="button"
                type="button"
                commandfor="demo-drawer-basic"
                command="show-modal"
            >
                Open drawer
            </button>
        </div>
    </div>

Side

Navigation

Slide-from-start drawer (default). Common for mobile nav.

Filters

Slide-from-end drawer. Common for filter panels and detail drawers.

<div>
                <brio-drawer>
                    <dialog class="drawer" id="demo-drawer-start">
                        <div class="drawer-panel">
                            <header>
                                <h3>Navigation</h3>
                                <button
                                    class="dismiss"
                                    type="button"
                                    commandfor="demo-drawer-start"
                                    command="--dismiss"
                                    aria-label="Close"
                                >
                                    &times;
                                </button>
                            </header>
                            <section>
                                <p>Slide-from-start drawer (default). Common for mobile nav.</p>
                            </section>
                        </div>
                    </dialog>
                </brio-drawer>

                <brio-drawer>
                    <dialog class="drawer is-end" id="demo-drawer-end">
                        <div class="drawer-panel">
                            <header>
                                <h3>Filters</h3>
                                <button
                                    class="dismiss"
                                    type="button"
                                    commandfor="demo-drawer-end"
                                    command="--dismiss"
                                    aria-label="Close"
                                >
                                    &times;
                                </button>
                            </header>
                            <section>
                                <p>
                                    Slide-from-end drawer. Common for filter panels and detail
                                    drawers.
                                </p>
                            </section>
                        </div>
                    </dialog>
                </brio-drawer>

                <div class="cluster is-tight">
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="demo-drawer-start"
                        command="show-modal"
                    >
                        Open start drawer
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="demo-drawer-end"
                        command="show-modal"
                    >
                        Open end drawer
                    </button>
                </div>
            </div>
        </div>
    </div>

Size

Small

Compact nav.

Large

Form-shaped drawer.

Extra large

Content-heavy panel.

<div>
                <brio-drawer>
                    <dialog class="drawer is-sm" id="demo-drawer-sm">
                        <div class="drawer-panel">
                            <header>
                                <h3>Small</h3>
                                <button
                                    class="dismiss"
                                    type="button"
                                    commandfor="demo-drawer-sm"
                                    command="--dismiss"
                                    aria-label="Close"
                                >
                                    &times;
                                </button>
                            </header>
                            <section><p>Compact nav.</p></section>
                        </div>
                    </dialog>
                </brio-drawer>

                <brio-drawer>
                    <dialog class="drawer is-lg" id="demo-drawer-lg">
                        <div class="drawer-panel">
                            <header>
                                <h3>Large</h3>
                                <button
                                    class="dismiss"
                                    type="button"
                                    commandfor="demo-drawer-lg"
                                    command="--dismiss"
                                    aria-label="Close"
                                >
                                    &times;
                                </button>
                            </header>
                            <section><p>Form-shaped drawer.</p></section>
                        </div>
                    </dialog>
                </brio-drawer>

                <brio-drawer>
                    <dialog class="drawer is-xl" id="demo-drawer-xl">
                        <div class="drawer-panel">
                            <header>
                                <h3>Extra large</h3>
                                <button
                                    class="dismiss"
                                    type="button"
                                    commandfor="demo-drawer-xl"
                                    command="--dismiss"
                                    aria-label="Close"
                                >
                                    &times;
                                </button>
                            </header>
                            <section><p>Content-heavy panel.</p></section>
                        </div>
                    </dialog>
                </brio-drawer>

                <div class="cluster is-tight">
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="demo-drawer-sm"
                        command="show-modal"
                    >
                        Open .is-sm
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="demo-drawer-lg"
                        command="show-modal"
                    >
                        Open .is-lg
                    </button>
                    <button
                        class="button is-outlined"
                        type="button"
                        commandfor="demo-drawer-xl"
                        command="show-modal"
                    >
                        Open .is-xl
                    </button>
                </div>
            </div>
        </div>
    </div>

Source comments

Drawer -- side panel overlay using native <dialog>

Structure -- semantic HTML carries the inner regions; .drawer-panel
stays as a class because it's a structural archetype, not a
semantic region (no native element means "the visible inner panel
of a modal"):

  <brio-drawer>
      <dialog class="drawer" id="my-drawer">
          <div class="drawer-panel">
              <header>            <-- title row, bordered separator
                  <h3>Title</h3>
                  <button class="dismiss" commandfor="my-drawer"
                          command="--dismiss" aria-label="Close">×</button>
              </header>
              <section>           <-- scrollable middle; <article> also accepted
                  …
              </section>
              <footer>            <-- right-aligned actions row
                  …
              </footer>
          </div>
      </dialog>
  </brio-drawer>

Body element: <section> for generic drawer content (canonical), or
<article> for self-contained compositions. Header/body/footer are
direct children of the panel, not the dialog.

Open with commandfor/command="show-modal". Close with command="--dismiss" (animated)
or command="close" (instant). Animated slide + backdrop fade via @starting-style.
Focus trapping, Escape, and backdrop click from native <dialog> (Escape and
backdrop click are intercepted by <brio-drawer> for the animated close path).

Architecture:

The <dialog class="drawer"> element is a full-viewport transparent
container -- it sits under the backdrop and catches the backdrop-
click dismissal at the viewport level. The *visible* drawer is
<div class="drawer-panel">, a child pinned to one edge via
position: fixed and animated via transform. That split lets the
panel carry the slide animation and chrome (radius, shadow,
border) while the dialog carries the modal semantics. The slide
animation targets the panel; brio-drawer.js queries it for
animated close.

Three states drive the panel transform:
  [open]              panel at transform: 0 (rest)
  :not([open])        panel off-screen (native closed)
  .is-closing         panel off-screen (animated close path;
                      added by <brio-drawer>, removed after the
                      transition completes, then .close() runs)

Browsers without @starting-style or discrete transitions skip
the animation and fall back to instant show/hide. Fully usable.

Reference

Source: src/css/drawer.css

Applies to

.drawer

Classes

ClassKindDescription
.is-closingvariantAnimated close state applied by brio-drawer before dialog.close()
.is-endvariantSlides from the end (right in LTR) instead of the start
.no-borderopt-outStrips all borders from the drawer and its slots
.is-smvariantNarrow drawer at 14rem
.is-lgvariantWide drawer at 24rem
.is-xlvariantExtra-wide drawer at 32rem

Slots

SlotDescription
.drawer-panelVisible sliding container pinned to one edge
.drawer-panel > headerTitle row with bordered separator
.drawer-panel > :is(section, article)scrollable middle, grows to fill the panel column
.drawer-panel > footerright-aligned action row, pinned to the bottom

Tokens

TokenDefaultDescription
--drawer-width18remWidth of the drawer panel
--drawer-bgvar(--color-surface)Background color for the panel
--drawer-border-colorvar(--color-border)Border color for the panel edge facing the page
--drawer-border-widthvar(--border-width-default)Border width for the panel edge facing the page
--drawer-header-border-colorvar(--color-border)Separator border color below the header
--drawer-footer-border-colorvar(--color-border)Separator border color above the footer
--drawer-colorvar(--color-text)Text color inside the panel
--drawer-radiusvar(--radius-sm)Border radius on the panel's page-facing corners
--drawer-title-font-sizevar(--ui-font-size-base)Font size for the drawer title heading