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

Dialog

A native dialog on the overlay surface behind a 1px overlay border and the backdrop; modal when shown, with trapped focus and Escape to close.

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

Live variants

default

Save changes?

Three settings changed since the last save. Unsaved changes are kept locally until you publish.

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

Markup
<j3w1-dialog id="example-dialog-default">
  <dialog class="dialog" role="alertdialog" aria-labelledby="example-dialog-default-dg-confirm-title" aria-describedby="example-dialog-default-dg-confirm-text">
    <div class="dialog-header">
      <h2 class="dialog-title" id="example-dialog-default-dg-confirm-title">Save changes?</h2>
      <button class="dialog-close" type="button" aria-label="Close">✕</button>
    </div>
    <div class="dialog-body">
      <p class="dialog-text" id="example-dialog-default-dg-confirm-text">Three settings changed since the last save. Unsaved changes are kept locally until you publish.</p>
    </div>
    <div class="dialog-actions">
      <button class="dialog-button" type="button" data-close="cancel">Keep editing</button>
      <button class="dialog-button dialog-button-primary" type="button" data-action="confirm">Save</button>
    </div>
    <p class="dialog-trap-note">Focus is trapped: Tab cycles inside the dialog; Escape closes it.</p>
  </dialog>
<button class="button" type="button" data-open="">Open dialog</button></j3w1-dialog>

alert-dialog

Delete profile "workstation"?

The profile and its two overlays are removed. This cannot be undone.

Focus is trapped: Tab cycles inside the dialog; Escape cancels.

Markup
<j3w1-dialog id="example-dialog-alert-dialog">
  <dialog class="dialog" role="alertdialog" aria-labelledby="example-dialog-alert-dialog-dg-delete-title" aria-describedby="example-dialog-alert-dialog-dg-delete-text">
    <div class="dialog-header">
      <h2 class="dialog-title" id="example-dialog-alert-dialog-dg-delete-title">Delete profile "workstation"?</h2>
      <button class="dialog-close" type="button" aria-label="Close">✕</button>
    </div>
    <div class="dialog-body">
      <p class="dialog-text" id="example-dialog-alert-dialog-dg-delete-text">The profile and its two overlays are removed. This cannot be undone.</p>
    </div>
    <div class="dialog-actions">
      <button class="dialog-button" type="button" data-close="cancel">Cancel</button>
      <button class="dialog-button dialog-button-destructive" type="button" data-action="delete">Delete profile</button>
    </div>
    <p class="dialog-trap-note">Focus is trapped: Tab cycles inside the dialog; Escape cancels.</p>
  </dialog>
<button class="button" type="button" data-open="">Open dialog</button></j3w1-dialog>

form

New profile

The profile starts from the default tokens.

Lowercase letters, digits and hyphens.

Focus is trapped: Tab cycles inside the dialog; Enter submits; Escape cancels.

Markup
<j3w1-dialog id="example-dialog-form">
  <dialog class="dialog" aria-labelledby="example-dialog-form-dg-form-title" aria-describedby="example-dialog-form-dg-form-text">
    <div class="dialog-header">
      <h2 class="dialog-title" id="example-dialog-form-dg-form-title">New profile</h2>
      <button class="dialog-close" type="button" aria-label="Close">✕</button>
    </div>
    <form class="dialog-body" method="dialog">
      <p class="dialog-text" id="example-dialog-form-dg-form-text">The profile starts from the default tokens.</p>
      <div class="dialog-field">
        <label class="dialog-field-label" for="example-dialog-form-dg-form-name">Profile name</label>
        <input class="dialog-field-input" id="example-dialog-form-dg-form-name" type="text" value="laptop" aria-describedby="example-dialog-form-dg-form-help" name="example-dialog-form-dg-form-name">
        <p class="dialog-field-help" id="example-dialog-form-dg-form-help">Lowercase letters, digits and hyphens.</p>
      </div>
      <div class="dialog-actions">
        <button class="dialog-button" type="button" data-close="cancel">Cancel</button>
        <button class="dialog-button dialog-button-primary" type="submit">Create</button>
      </div>
    </form>
    <p class="dialog-trap-note">Focus is trapped: Tab cycles inside the dialog; Enter submits; Escape cancels.</p>
  </dialog>
<button class="button" type="button" data-open="">Open dialog</button></j3w1-dialog>

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/dialog.css';
import '@j3w1/ui/register/dialog';

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 dialog --out ./vendor/j3w1/dialog

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

Dialog dialog

  • Family: Feedback and overlays
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: native <dialog> opened with showModal; role=alertdialog for confirmations; named by its heading, described by its first paragraph — APG pattern
  • specified
  • demonstrated
  • test implemented

A native dialog on the overlay surface behind a 1px overlay border and the backdrop; modal when shown, with trapped focus and Escape to close.

Report an issue with this component

Open component workbench

View source and copy recipe · Download standalone example — visual-only; modal behavior is host-owned.

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.dialogobserveduse30
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.
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.
button.textcolor.action.secondary.textapproveduse#ffa2a7D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
button.bordercolor.action.secondary.borderapproveduse#986f72D-041 action.secondary.border: color.primitive.modern.control.
button.bg-hovercolor.action.secondary.hover-bgobserveduse#630f0dSecondary button hover.
primary.bgcolor.action.primary.bgapproveduse#7d1310Primary button fill; D-026 darkened it off color12, which stays fixed as heritage ANSI 12.
primary.textcolor.action.primary.textapproveduse#ffa2a7Primary action labels: bright rose across rest, hover and pressed states (D-033).
primary.bg-hovercolor.action.primary.hover-bgobserveduse#911410Primary button hover; pair with action.primary.text (D-033).
destructive.bgcolor.action.destructive.filled-bgobserveduse#dc282eConfirm-dialog destructive fill.
destructive.textcolor.action.destructive.filled-textobserveduse#f9faf9Text on the destructive fill.
destructive.bg-hovercolor.action.destructive.hover-bgobserveduse#dc282eDestructive button hover fill.
field.bgcolor.surface.inputapproveduse#000000Form-control fill.
field.bordercolor.border.controlapproveduse#c81a1aD-041 owner correction: red control and floating-frame borders, distinct from rose text.
field.labelcolor.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.
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).

StateConfirmAlert dialogForm
default

Save changes?

Three settings changed since the last save. Unsaved changes are kept locally until you publish.

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

Delete profile "workstation"?

The profile and its two overlays are removed. This cannot be undone.

Focus is trapped: Tab cycles inside the dialog; Escape cancels.

New profile

The profile starts from the default tokens.

Lowercase letters, digits and hyphens.

Focus is trapped: Tab cycles inside the dialog; Enter submits; Escape cancels.

open
closed
focus-trapped
hover
focus-visible
reduced-motion

Purpose

A question or small task the page cannot continue without: confirm a destructive action, name a new profile, sign in again. It takes the whole screen’s attention, so it is short, clearly titled and always offers a way out.

Anatomy

Confirmations take no fixed tone (D-015): an ordinary one uses primary, a destructive one the filled destructive button. The form variant holds a labelled text field on color.surface.input.

States

StateVisualNon-colour channel
defaultthe dialog open on its backdropopen; the page behind is inert
openas default; opacity 0 → 1 within 150 ms on capable hostsopen; focus inside the dialog
closeddialog and backdrop absentno open; focus back on the opener
focus-trappedwhen it holds focus, the dialog carries the container ring, 2px solid color.interaction.focus.ring-container at −3px; the note says Tab cyclesTab never leaves; the note text
hoverClose → color.action.tertiary.hover-bg; other buttons take their tone’s hovercursor: pointer
focus-visible1px dashed color.interaction.focus.ring at −2px on the focused control; primary uses color.interaction.focus.ring-container, destructive color.action.destructive.filled-text (D-015)the ring
reduced-motionno opacity transition; present or absentprefers-reduced-motion

A dialog is never disabled; a busy dialog disables its confirm button and shows the ⋯ glyph on it.

Keyboard

As in the key table. Enter on the dialog itself never triggers a destructive confirm. On open, focus goes to the first focusable element, or to the dialog when that element is destructive.

Accessibility

Title and first paragraph link through aria-labelledby and aria-describedby. The theme never re-implements the trap on a non-modal dialog. The backdrop is decorative and cancels on click only when Close is also present. Text meets 4.5:1; the overlay border and rings 3:1.

Portability

A toolkit with a native modal window uses it with the overlay border on the frame and records that the backdrop is the host’s; one without a top layer draws the backdrop as a full-window overlay under the dialog.

Non-examples

A glowing or shadowed card. Rounded corners. Sliding or scaling in. <dialog> shown with show() and a hand-written trap. No title, or the title only in the accessible name. A destructive confirm as the default Enter action. A backdrop that closes the dialog with no Close button. A dialog stacked on a dialog.

Contrast report

23 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
dialog default textdefaulttextcolor.text.default #e99499color.surface.overlay #1c10108.104.5pass
dialog default borderdefaultuicolor.border.overlay #c81a1acolor.surface.overlay #1c10103.203pass
dialog open textopentextcolor.text.default #e99499color.surface.overlay #1c10108.104.5pass
dialog open borderopenuicolor.border.overlay #c81a1acolor.surface.overlay #1c10103.203pass
dialog focus-trapped textfocus-trappedtextcolor.text.default #e99499color.surface.overlay #1c10108.104.5pass
dialog focus-trapped borderfocus-trappeduicolor.border.overlay #c81a1acolor.surface.overlay #1c10103.203pass
dialog focus-trapped outlinefocus-trappeduicolor.interaction.focus.ring-container #ffa2a7color.surface.overlay #1c10109.713pass
dialog hover texthovertextcolor.action.tertiary.text #e99499color.action.tertiary.hover-bg #1c0a098.354.5pass
dialog focus-visible textfocus-visibletextcolor.action.tertiary.text #e99499color.surface.overlay #1c10108.104.5pass
dialog focus-visible outlinefocus-visibleuicolor.interaction.focus.ring #e53935color.surface.overlay #1c10104.393pass
dialog reduced-motion textreduced-motiontextcolor.text.default #e99499color.surface.overlay #1c10108.104.5pass
dialog 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
secondary button text on the overlay surface—textcolor.action.secondary.text #ffa2a7color.surface.overlay #1c10109.714.5pass
secondary button boundary on the overlay surface—uicolor.action.secondary.border #986f72color.surface.overlay #1c10104.293pass
primary button text—textcolor.action.primary.text #ffa2a7color.action.primary.bg #7d13105.574.5pass
destructive confirm text on its fill—textcolor.action.destructive.filled-text #f9faf9color.action.destructive.filled-bg #dc282e4.584.5pass
destructive fill against the overlay surface—uicolor.action.destructive.filled-bg #dc282ecolor.surface.overlay #1c10103.883pass
ring on the primary fillfocus-visibleuicolor.interaction.focus.ring-container #ffa2a7color.action.primary.bg #7d13105.573pass
ring on the destructive fillfocus-visibleuicolor.action.destructive.filled-text #f9faf9color.action.destructive.filled-bg #dc282e4.583pass
form field text—textcolor.text.default #e99499color.surface.input #0000009.164.5pass
form field boundary on the overlay surface—uicolor.border.control #c81a1acolor.surface.overlay #1c10103.203pass

Keys

KeyAction
Tab / Shift+TabCycles through the dialog's focusable elements and never leaves it while open.
EscapeCloses the dialog (cancel) and returns focus to the element that opened it.
EnterIn a form dialog, submits; otherwise activates the focused button only.
SpaceActivates the focused button.

For agents

Component JSON ·Implementation brief ·Build a task kit ·

Related: drawer alert toast button text-field popover

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