j3w1 / DrawerVue · HTML · React · Astro

J3W1 / DESIGN SYSTEM

Drawer

A full-height modal panel anchored to the start or end edge; a native dialog on the overlay surface with a 1px overlay border on its inner edge.

stable · LIGHT DOM · 1.1.0

Light DOM retains static content, native semantics, label relationships and host composition without duplicating controls.

Live variants

start

Sections

Focus is trapped: Tab cycles inside the drawer; Escape closes it.

Example destination: dw foundations

Example destination: dw actions

Example destination: dw forms

Example destination: dw feedback

<j3w1-drawer id="example-drawer-start">
  <dialog class="drawer drawer-start" aria-labelledby="example-drawer-start-dw-nav-title">
    <div class="drawer-header">
      <h2 class="drawer-title" id="example-drawer-start-dw-nav-title">Sections</h2>
      <button class="drawer-close" type="button" aria-label="Close">✕</button>
    </div>
    <nav class="drawer-body" aria-label="Sections">
      <ul class="drawer-list">
        <li class="drawer-item"><a class="drawer-link" href="#example-drawer-start-dw-foundations" aria-current="page">Foundations</a></li>
        <li class="drawer-item"><a class="drawer-link" href="#example-drawer-start-dw-actions">Actions</a></li>
        <li class="drawer-item"><a class="drawer-link" href="#example-drawer-start-dw-forms">Forms</a></li>
        <li class="drawer-item"><a class="drawer-link" href="#example-drawer-start-dw-feedback">Feedback</a></li>
      </ul>
    </nav>
    <p class="drawer-trap-note">Focus is trapped: Tab cycles inside the drawer; Escape closes it.</p>
  </dialog>
<button class="button" type="button" data-open="">Open drawer</button><p id="example-drawer-start-dw-foundations" tabindex="-1" class="j3w1-example-target">Example destination: dw foundations</p><p id="example-drawer-start-dw-actions" tabindex="-1" class="j3w1-example-target">Example destination: dw actions</p><p id="example-drawer-start-dw-forms" tabindex="-1" class="j3w1-example-target">Example destination: dw forms</p><p id="example-drawer-start-dw-feedback" tabindex="-1" class="j3w1-example-target">Example destination: dw feedback</p></j3w1-drawer>

end

Filters

Narrow the table to the rows that match every filter.

Focus is trapped: Tab cycles inside the drawer; Escape closes it.

<j3w1-drawer id="example-drawer-end">
  <dialog class="drawer drawer-end" aria-labelledby="example-drawer-end-dw-filter-title">
    <div class="drawer-header">
      <h2 class="drawer-title" id="example-drawer-end-dw-filter-title">Filters</h2>
      <button class="drawer-close" type="button" aria-label="Close">✕</button>
    </div>
    <div class="drawer-body">
      <p class="drawer-text">Narrow the table to the rows that match every filter.</p>
      <ul class="drawer-list">
        <li class="drawer-item"><label class="drawer-check"><input class="drawer-checkbox" type="checkbox" checked="" name="example-drawer-end-value"> Only R1</label></li>
        <li class="drawer-item"><label class="drawer-check"><input class="drawer-checkbox" type="checkbox" name="example-drawer-end-value"> Only tested</label></li>
        <li class="drawer-item"><label class="drawer-check"><input class="drawer-checkbox" type="checkbox" name="example-drawer-end-value"> Hide deprecated</label></li>
      </ul>
    </div>
    <p class="drawer-trap-note">Focus is trapped: Tab cycles inside the drawer; Escape closes it.</p>
  </dialog>
<button class="button" type="button" data-open="">Open drawer</button></j3w1-drawer>

Install and register

Use the exact version. If npm publication is pending, install the release tarball from the installation guide.

npm install --save-exact @j3w1/ui@1.1.0
import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/drawer.css';
import '@j3w1/ui/register/drawer';

Insert the maintained markup above after loading these imports. Its native children provide accessible names and form behavior; the empty custom tag alone does not create a control.

Vue SFC, React, Astro and plain HTML integration →

Copy the complete implementation

npx --package=@j3w1/ui@1.1.0 j3w1-ui copy drawer --out ./vendor/j3w1/drawer

The CLI verifies every file before writing and refuses overwrites. Serve the output over HTTP and open index.html. Keep its modules, CSS, tokens and licence notices together.

Public API

attributes

NameType / signatureMeaning
disabledCustomEventDisable the native controls owned by this instance.
loadingCustomEventMark the primary control busy and prevent duplicate activation.

properties

NameType / signatureMeaning
disabledbooleanDelegates disabled state to native children.
namestringNative control name; application form keys remain explicit.
openbooleanNative modal state.
returnValuestringNative dialog result. Read only.

methods

NameType / signatureMeaning
refresh(): voidReconnect behavior after replacing native child structure.
focus(options?: FocusOptions): voidFocus the first usable native control.
show(): voidOpen using native showModal and remember the opener.
close(value?: string): voidClose with a result value.

events

NameType / signatureMeaning
j3w1-openCustomEventThe modal opened.
j3w1-closeCustomEventThe modal closed and restored available opener focus.
j3w1-cancelCustomEventNative cancel request; prevent default to keep the modal open.
j3w1-actionCustomEventAn explicit dialog action; prevent default to keep it open.

Dependencies and verification

Registered components: none. Style dependencies: button.

Package presence establishes an available implementation. Actual passes depend on the tested artifact and environment. Read specification execution evidence; read packed-consumer evidence; inspect the complete state matrix.

Full implementation manifest, API and token dependency closure

Canonical specification

Purpose

A panel that opens from the side to hold navigation or a task on narrow screens, or a secondary form on wide ones. It is a modal dialog with a different shape: full height, anchored to the start or end edge, with a single visible border on the edge that faces the page. Below 900px the sidebar collapses into a drawer; above it, a drawer holds tasks that need more room than a dialog.

Anatomy

The backdrop, color.surface.backdrop over the page; the panel on color.surface.overlay with a 1px color.border.overlay on its inner edge; the header with the title in color.text.bright and Close; the body, rows divided by color.border.divider. The demonstration renders the panel inside a stage of fixed height standing in for the viewport.

States

StateVisualNon-colour channel
defaultthe panel open at its edge on the backdropopen; the page behind is inert
openas default; opacity 0 → 1 within 150 ms on capable hosts; never a slideopen; focus inside the panel
closednothing: the panel and the backdrop are absentno open; focus back on the opener
focus-trappedthe panel carries the container ring, 2px solid color.interaction.focus.ring-container at −3px, when it holds focus; the note says Tab cyclesTab never leaves; the note text
reduced-motionno opacity transition; the panel is simply present or absentprefers-reduced-motion

Items inside the drawer take the states of the list or navigation they belong to; Close takes the tertiary button’s hover and ring.

Keyboard

Tab and Shift+Tab cycle inside the panel; the page behind is inert. Escape closes and returns focus to the opener. Enter or Space on a navigation item navigates and closes. On open, focus goes to the first focusable element, which is the first item or Close.

Accessibility

The panel is named by its title through aria-labelledby. showModal() supplies the top layer and inertness; the theme never re-implements the trap on a non-modal element or on a plain aside. The backdrop is decorative; a click on it may close the drawer only because Close is also present. Both edges use logical properties, so the panel and its border mirror in RTL with no extra rules. Contrast: text 7.92:1 and title 9.49:1 on the overlay surface, the border 4.30:1, the ring 4.30:1, hovered items 11.41:1 on the strong hover fill.

Portability

A full-height box with one border and a dimmed backdrop. Toolkits without a top layer draw the backdrop as a full-window overlay under the panel; toolkits with a native sidebar keep it non-modal and record that it is a sidebar, not a drawer.

Non-examples

A panel that slides in from the edge. A drawer with a shadow or a rounded inner corner. A drawer that is a plain aside with a hand-written focus trap. A bottom sheet with a drag handle. A drawer with no Close button. A drawer that stays open under a dialog. A translucent panel over page content.

j3w1 / command

  • SPEC Overview
  • SPEC Foundations
  • SPEC Components
  • SPEC Patterns
  • SPEC Tokens
  • SPEC Tools
  • SPEC Implement
  • SPEC For agents
  • SPEC Ports
  • SPEC Releases
  • DEMO Vue application demo
  • SPEC Complete UI theme specification