j3w1 / theme

j3w1 / theme4.0.0

j3w1 / command

  • SPEC Overview
  • SPEC Foundations
  • SPEC Components
  • SPEC Patterns
  • SPEC Tokens
  • SPEC Tools
  • SPEC Workbench
  • SPEC Form builder
  • SPEC Task kit
  • SPEC Recipes
  • SPEC Figma bridge
  • SPEC Report an issue
  • SPEC Implement
  • SPEC For agents
  • SPEC Ports
  • SPEC Releases
  • SPEC Specification
  • DEMO Vue application demo

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 · 4.0.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

Markup
<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.

Markup
<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@4.0.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@4.0.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

Drawer drawer

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <dialog> opened with showModal, anchored to an inline edge; named by its heading; Escape closes — APG pattern
  • specified
  • demonstrated

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.

Report an issue with this component

Tokens

Focus a role to inspect its values; follow its link for persistent usage and source details.

PartRoleValueUse
backdrop.bgcolor.surface.backdropproposeduse-and-reportD-008rgb(0 0 0 / 65%)Behind modal dialogs.
root.bgcolor.surface.overlayapproveduse#1c1010D-041 surface.overlay: color.primitive.modern.overlay.
root.bordercolor.border.overlayapproveduse#c81a1aD-041 owner correction: red control and floating-frame borders, distinct from rose text.
root.ringcolor.interaction.focus.ring-containerobserveduse#ffa2a7Focus colour for containers and explicitly mapped filled controls (D-015); component rules determine ring geometry.
root.zz.drawerobserveduse20
title.textcolor.text.brightapproveduse#ffa2a7D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
text.textcolor.text.defaultapproveduse#e99499D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
body.dividercolor.border.dividerapproveduse#482b2bD-041 border.divider: color.primitive.modern.divider.
item.textcolor.text.defaultapproveduse#e99499D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
item.bg-hovercolor.interaction.hover.bg-strongapproveduse#1c1010D-041 interaction.hover.bg-strong: color.primitive.modern.hover.
item.text-hovercolor.text.link-hoverobserveduse#f4eeeeLink text on hover, over interaction.hover.bg-strong.
close.textcolor.action.tertiary.textapproveduse#e99499D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
close.bg-hovercolor.action.tertiary.hover-bgobserveduse#1c0a09Ghost and icon button hover.
close.ringcolor.interaction.focus.ringobserveduse#e539351px dashed focus ring on controls and rows.
note.textcolor.text.mutedapproveduse#d4868bD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.

State matrix

Every declared state and combination, statically rendered; the default cell is live. Sizes: compact, comfortable (switch with the density control above).

StateStart edgeEnd edge
default

Sections

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

Filters

Narrow the table to the rows that match every filter.

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

open
closed
focus-trapped
reduced-motion

Purpose

A modal dialog shaped as a full-height side panel, for navigation or a task. Below 900px the sidebar collapses into a drawer; above it, a drawer holds tasks that need more room than a dialog.

Anatomy

Parts as listed in the anatomy; the overlay border is the only visible edge.

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
closedpanel and backdrop absentno open; focus back on the opener
focus-trappedwhile it holds focus, the panel carries the 2px solid color.interaction.focus.ring-container ring at −3px; the note says Tab cyclesTab never leaves; the note text
reduced-motionno opacity transition; present or absentprefers-reduced-motion

Items take the states of their list or navigation; Close takes the tertiary button’s hover and ring.

Keyboard

As in the key table. On open, focus goes to the first focusable element, the first item or Close.

Accessibility

Named by its title through aria-labelledby. Never re-implement the trap on a non-modal element or a plain aside. The backdrop is decorative; a click on it may close the drawer only because Close is also present. Logical properties mirror the panel and its border in RTL. Text meets 4.5:1; the border and ring 3:1.

Portability

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. A shadow or a rounded inner corner. A plain aside with a hand-written focus trap. A bottom sheet with a drag handle. No Close button. A drawer that stays open under a dialog. A translucent panel over page content.

Contrast report

15 declared pairs measured on resolved sRGB values with the WCAG 2.x formula; 0 waived (decorative only), 0 failing. A pass is a design target for the named role, not an application-wide conformance claim.

PairStateKindForegroundBackgroundRatioMinResult
drawer default textdefaulttextcolor.text.default #e99499color.surface.overlay #1c10108.104.5pass
drawer default borderdefaultuicolor.border.overlay #c81a1acolor.surface.overlay #1c10103.203pass
drawer open textopentextcolor.text.default #e99499color.surface.overlay #1c10108.104.5pass
drawer open borderopenuicolor.border.overlay #c81a1acolor.surface.overlay #1c10103.203pass
drawer focus-trapped textfocus-trappedtextcolor.text.default #e99499color.surface.overlay #1c10108.104.5pass
drawer focus-trapped borderfocus-trappeduicolor.border.overlay #c81a1acolor.surface.overlay #1c10103.203pass
drawer focus-trapped outlinefocus-trappeduicolor.interaction.focus.ring-container #ffa2a7color.surface.overlay #1c10109.713pass
drawer reduced-motion textreduced-motiontextcolor.text.default #e99499color.surface.overlay #1c10108.104.5pass
drawer reduced-motion borderreduced-motionuicolor.border.overlay #c81a1acolor.surface.overlay #1c10103.203pass
title on the overlay surface—textcolor.text.bright #ffa2a7color.surface.overlay #1c10109.714.5pass
note on the overlay surface—textcolor.text.muted #d4868bcolor.surface.overlay #1c10106.704.5pass
close button on the overlay surface—textcolor.action.tertiary.text #e99499color.surface.overlay #1c10108.104.5pass
ring on the overlay surface—uicolor.interaction.focus.ring #e53935color.surface.overlay #1c10104.393pass
hovered item—textcolor.text.link-hover #f4eeeecolor.interaction.hover.bg-strong #1c101016.194.5pass
row dividers (decorative)—uicolor.border.divider #482b2bcolor.surface.overlay #1c10101.461pass

Keys

KeyAction
Tab / Shift+TabCycles inside the drawer and never leaves it while open.
EscapeCloses the drawer and returns focus to the element that opened it.
Enter / SpaceActivates the focused item or button; a navigation item closes the drawer after navigating.

For agents

Component JSON ·Implementation brief ·Build a task kit ·

Related: dialog sidebar-nav menu toolbar

Stress fixtures: FX-LONG FX-320 FX-ZOOM-200 FX-I18N FX-RTL FX-RM FX-HC FX-OVERFLOW FX-STATE-MATRIX