Theme
Design your own
On this page (10)
Component Skill — components/window/component-skill.md

Native basis

A non-modal <dialog class="window" open> in a .window-desktop; the controls are a <form method="dialog">, the resize handle is CSS resize.

Web Platform APIs

dialog.show()method="dialog"resizesetPointerCapture()touch-action

Classes

.window-desktop.window.window-titlebar.window-icon.window-title.window-controls.window-toolbar.window-body.window-statusbar

Data attributes

data-chrome (windows, mac, linux, retro), data-resizable, data-maximized, data-minimized, data-active (set by the runtime), data-flush on the body; --window-x / --window-y / --window-w / --window-h; events window-focus, window-move, close; API df$.shadcn.win.

§Window

Drag the title bar to move it (it never leaves the desktop for good), double-click it to maximize, − rolls it up to its bar, □ fills the desktop, × closes it - a native <form method='dialog'>. The corner handle resizes (CSS resize). Focus the title bar and use the arrow keys to move it by keyboard.

§Several windows

Press any window - its bar, its content - and it comes to the front; the others dim their title (data-active marks the front one). Stacking is shared across the page.

§Chrome

data-chrome: windows (the default - wide controls, a red × on hover), mac (traffic lights on the left, glyphs on hover, centred title), linux (GNOME round buttons, centred title) and retro (a bevelled 9x window). Same markup, same behaviour.

§Driven from script

df$.shadcn.win.create() builds a window (title, icon, content, position, size, chrome) in the first desktop; cascade() and tile() arrange the open ones; close() takes an element, id or selector. The log reads window-focus, window-move and close.

§Window states

The State API per window: default (open, normal size - also reopens a closed one), maximized, minimized (rolled up to the bar) and closed. The × and close() land in closed too - the state follows the native dialog.

§A desktop app: an editor with its toolbar

The editor window carries its app toolbar under the title bar (.window-toolbar): a ghost menubar - File, Edit, Window, Help - and tool buttons, all driving the windows through df$.shadcn.win (Window → Tile / Cascade / Maximize, Help → About opens a retro window). The editor opens on the left, the Preview on the right; the editor is a textarea over a Shiki-highlighted copy (loaded from esm.sh, like these docs), re-highlighted as you type; the status bar follows the caret and the Preview window renders the page live.

§States

Named states via the shared State API, driven per window through the bound api:

  • default - open at its normal size; reopens a closed window, { x, y } moves it
  • maximized - fills the desktop
  • minimized - rolled up to its title bar
  • closed - the dialog is closed; also entered when the × or close() closes it

The first example carries data-state-demo; bun run screenshots drives it via el.api.setState(name) and captures screenshots/{mode}/window-{state}.png.

Machine contract - verified against window.schema.json by bun run verify:

StateTypeValuesDefaultDescription
maximizedbooleantrue, falsefalseFills the desktop.
minimizedbooleantrue, falsefalseRolled up to its title bar.
closedbooleantrue, falsefalseThe dialog is closed - also by the × or close().

§API

Generated from window.ts and the shared State API - the descriptions are their JSDoc, the types are checked by the compiler.

States

type WindowState = 'default' | 'maximized' | 'minimized' | 'closed' - setState(name, config) takes the config of the state it names.

StateDescription
default
Open at its normal size (opens a closed window).
Config fieldTypeDescription
x?numbermove it: the left edge, px inside its desktop (with y)
y?numbermove it: the top edge, px inside its desktop (with x)
maximized
Fills the desktop.
Config fieldTypeDescription
x?numberreported by getState() until it closes: the left edge set last, px
y?numberreported by getState() until it closes: the top edge set last, px
minimized
Rolled up to its title bar.
Config fieldTypeDescription
x?numberreported by getState() until it closes: the left edge set last, px
y?numberreported by getState() until it closes: the top edge set last, px
closed
Closed - also after the close button or close(); it reopens at its normal size.

No config.

Every element

MemberDescription
el.api.setState<S extends WindowState>(name: S, config?: WindowStateConfigs[S]): unknown
Enter a state: the DOM work runs (also when it is the current state), the store records it.
ArgumentTypeDescription
nameSa declared state (an unknown name throws)
config?WindowStateConfigs[S]that state's config (merged into the stored one when the component merges)

Returns unknown - what the state's DOM work returned - a Promise for an async state (or await settled())

el.api.getState(): { name: WindowState; config: WindowStateConfigs[WindowState]; model?: ElementModel }
The state the element shows now - read back from the DOM, so it includes what the user changed.

Returns { name: WindowState; config: WindowStateConfigs[WindowState]; model?: ElementModel } - the state's name, its config and the authored markup model render() starts from

el.api.render(state?: { name: WindowState; config: WindowStateConfigs[WindowState]; model?: ElementModel }): string
The element's markup in a state - the authored markup with that state applied; a pure function of the state.
ArgumentTypeDescription
state?{ name: WindowState; config: WindowStateConfigs[WindowState]; model?: ElementModel }a state as getState() returns it (default: the current one)

Returns string - the element's outer HTML in that state

el.api.settled(): Promise<void>
Wait for the last state's DOM work (async states: a diagram rendering, a chart mounting).

Returns Promise<void> - resolves when nothing is pending

el.store: Store<{ name: WindowState; config: WindowStateConfigs[WindowState] }>A defuss-store store of the element's state - subscribe to follow every change (also the user's), set it to drive the component.

Registry

MemberDescription
df$.shadcn.windowApi.setState<S extends WindowState>(el: HTMLElement, name: S, config?: WindowStateConfigs[S]): unknown
Enter a state: the DOM work runs (also when it is the current state), the store records it.
ArgumentTypeDescription
elHTMLElementthe component's element
nameSa declared state (an unknown name throws)
config?WindowStateConfigs[S]that state's config (merged into the stored one when the component merges)

Returns unknown - what the state's DOM work returned - a Promise for an async state (await it, or el.api.settled())

df$.shadcn.windowApi.getState(el: HTMLElement): { name: WindowState; config: WindowStateConfigs[WindowState]; model?: ElementModel }
The state the element shows now - read back from the DOM, so it includes what the user changed.
ArgumentTypeDescription
elHTMLElementthe component's element

Returns { name: WindowState; config: WindowStateConfigs[WindowState]; model?: ElementModel } - the state's name, its config and the authored markup model render() starts from

df$.shadcn.windowApi.render(state: { name: WindowState; config: WindowStateConfigs[WindowState]; model?: ElementModel }): string
The element's markup in a state - the authored markup with that state applied; a pure function of the state.
ArgumentTypeDescription
state{ name: WindowState; config: WindowStateConfigs[WindowState]; model?: ElementModel }a state as getState() returns it (with its model)

Returns string - the element's outer HTML in that state

df$.shadcn.windowApi.store(el: HTMLElement): Store<{ name: WindowState; config: WindowStateConfigs[WindowState] }>
The element's store (bindComponent made it).
ArgumentTypeDescription
elHTMLElementthe component's element

Returns Store<{ name: WindowState; config: WindowStateConfigs[WindowState] }> - a defuss-store store of { name, config } - subscribe to follow every change, set it to drive the component

df$.shadcn.windowApi.commit<S extends WindowState>(el: HTMLElement, name: S, config?: WindowStateConfigs[S]): void
Record a state the element reached on its own (no DOM work) - for a component's own handlers.
ArgumentTypeDescription
elHTMLElementthe component's element
nameSthe state it is in
config?WindowStateConfigs[S]its config
df$.shadcn.windowStates: WindowState[]The declared states, 'default' first: default, maximized, minimized, closed.

df$.shadcn.win

MemberDescription
create(options: WindowCreateOptions = {}): HTMLDialogElement
Builds a window element from options - the shape the skill documents.
ArgumentTypeDescription
optionsWindowCreateOptions = {}title, body, place, size, look and where it opens

Returns HTMLDialogElement - the new window (a <dialog class="window">), open unless focus is false

open(target: string | HTMLElement, config: { x?: number; y?: number } = {}): HTMLDialogElement | null
Open a window (closed, minimized or not shown yet) - config is the state's config.
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector
config{ x?: number; y?: number } = {}where it opens: { x, y } px

Returns HTMLDialogElement | null - the window, null when the target matches none

close(target: string | HTMLElement): HTMLDialogElement | null
Close it (the closed state).
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector

Returns HTMLDialogElement | null - the window, null when the target matches none

focus(target: string | HTMLElement): HTMLDialogElement | null
Bring it to the front (the active window).
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector

Returns HTMLDialogElement | null - the window, null when the target matches none

move(target: string | HTMLElement, x: number, y: number): WindowPosition | null
Move it to x, y (px, inside its desktop).
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector
xnumberthe left edge, px
ynumberthe top edge, px

Returns WindowPosition | null - where it landed (kept reachable inside its desktop), null when the target matches none

resize(target: string | HTMLElement, width: number | string, height?: number | string): HTMLDialogElement | null
Size it: width (and height) as px numbers or CSS lengths.
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector
widthnumber | stringpx, or a CSS length
height?number | stringpx, or a CSS length; omitted, the height stays

Returns HTMLDialogElement | null - the window, null when the target matches none

maximize(target: string | HTMLElement): HTMLDialogElement | null
Fill the desktop.
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector

Returns HTMLDialogElement | null - the window, null when the target matches none

minimize(target: string | HTMLElement): HTMLDialogElement | null
Minimize it to the taskbar.
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector

Returns HTMLDialogElement | null - the window, null when the target matches none

restore(target: string | HTMLElement): HTMLDialogElement | null
Back to its normal size and place.
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector

Returns HTMLDialogElement | null - the window, null when the target matches none

toggleMaximize(target: string | HTMLElement): HTMLDialogElement | null
Maximize it, or restore it when it is maximized.
ArgumentTypeDescription
targetstring | HTMLElementthe .window element, its id or a selector

Returns HTMLDialogElement | null - the window, null when the target matches none

active(): HTMLDialogElement | undefined
The window in front.

Returns HTMLDialogElement | undefined - the active open window, undefined when none is open

list(scope?: HTMLElement | string, all: boolean = false): HTMLDialogElement[]
Windows (open unless `all`) inside `scope` (default: the page).
ArgumentTypeDescription
scope?HTMLElement | stringa desktop element, its id or a selector (default: the page)
allboolean = falsetrue: closed windows too

Returns HTMLDialogElement[] - the windows, in document order

cascade(scope?: HTMLElement | string, step: number = 28): void
Steps the open windows diagonally from the top-left, front-most last.
ArgumentTypeDescription
scope?HTMLElement | stringa desktop element, its id or a selector (default: the page)
stepnumber = 28px between two windows (default 28)
tile(scope?: HTMLElement | string): void
Lays the open windows side by side in a grid that fills their desktop.
ArgumentTypeDescription
scope?HTMLElement | stringa desktop element, its id or a selector (default: the page)

Events

EventDescription
window-focus
Fires when a window comes to the front - its title.

detail: WindowFocusDetail

FieldTypeDescription
titlestringthe title of the window now in front
window-move
Fires after a window was dragged (or moved with the keyboard) - its position.

detail: WindowPosition

FieldTypeDescription
xnumberfrom the desktop's left edge
ynumberfrom the desktop's top edge

Types

TypeDescription
WindowCreateOptions
What create() takes - the shape the skill documents.
FieldTypeDescription
title?stringthe title bar text (default 'Untitled')
icon?stringa Lucide icon name for the title bar
content?Node | stringthe body: a node, or text
html?stringthe body as markup (used when content is not a node)
statusbar?stringa status bar line
id?stringthe window's id
x?number | stringleft edge: px, or a CSS length (default: cascaded from the windows before it)
y?number | stringtop edge: px, or a CSS length
width?number | stringwidth: px, or a CSS length
height?number | stringheight: px, or a CSS length
chrome?'windows' | 'mac' | 'linux' | 'retro'the look of the title bar
resizable?booleanthe native resize handle (default true)
parent?HTMLElement | stringthe desktop to open in: element, id or selector (default: the .window-desktop, else the body)
focus?booleanopen in front, active (default true)
flush?booleana body without padding (an app inside)
WindowFocusDetail
What window-focus carries.
FieldTypeDescription
titlestringthe title of the window now in front
WindowPosition
A window's place inside its desktop, px.
FieldTypeDescription
xnumberfrom the desktop's left edge
ynumberfrom the desktop's top edge

§CSS view file

/* -- Window component --------------------------------------------
   A desktop-style window: a non-modal <dialog> with a title bar (icon,
   title, minimize / maximize / close), moved by dragging the bar, raised to
   the front on click, resized natively. Chrome styles after Windows, macOS,
   Linux (GNOME) and a retro 9x look. The controls are a
   <form method="dialog">, so the × closes the window without script. */
@layer components {
  /* the area windows live in: positioned, clipped - a desktop */
  .window-desktop {
    position: relative;
    overflow: hidden;
    min-height: 18rem;
    border-radius: var(--radius-lg);
    background:
      radial-gradient(circle at 1px 1px, color-mix(in oklch, var(--foreground) 12%, transparent) 1px, transparent 0) 0 0 / 1.25rem 1.25rem,
      var(--muted);
    isolation: isolate;
  }
  .window {
    /* the UA dialog defaults (centered, padded, bordered) - replaced */
    --_titlebar: 2.25rem;
    --_ctl: 2.75rem;
    position: absolute;
    inset: auto;
    left: var(--window-x, 2rem);
    top: var(--window-y, 2rem);
    box-sizing: border-box;
    width: var(--window-w, 24rem);
    height: var(--window-h, auto);
    max-width: none;
    max-height: none;
    min-width: 12rem;
    margin: 0;
    padding: 0;
    display: none;
    flex-direction: column;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--card);
    color: var(--card-foreground);
    font-family: var(--font-sans);
    font-size: 0.875rem;
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    transition: box-shadow 150ms;
    &[open] { display: flex; }
    /* native resize handle, bottom-right */
    &[data-resizable] {
      resize: both;
      min-height: calc(var(--_titlebar) + 4rem);
    }
    /* -- Title bar ---------------------------------------------------- */
    & > .window-titlebar {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      flex: none;
      height: var(--_titlebar);
      padding-inline-start: 0.75rem;
      background: var(--muted);
      border-bottom: 1px solid var(--border);
      cursor: default;
      user-select: none;
      touch-action: none;
      &:focus-visible {
        outline: 2px solid var(--ring);
        outline-offset: -2px;
      }
    }
    & .window-icon {
      flex: none;
      width: 1rem;
      height: 1rem;
      object-fit: contain;
      color: var(--muted-foreground);
    }
    & .window-title {
      flex: 1;
      min-width: 0;
      margin: 0;
      overflow: hidden;
      font: inherit;
      font-size: 0.8125rem;
      font-weight: 500;
      white-space: nowrap;
      text-overflow: ellipsis;
    }
    /* -- Controls: CSS-drawn glyphs --------------------------------------- */
    & .window-controls {
      display: flex;
      align-self: stretch;
      flex: none;
      margin: 0;
    }
    & .window-controls > button {
      position: relative;
      box-sizing: border-box;
      width: var(--_ctl);
      height: 100%;
      margin: 0;
      padding: 0;
      border: 0;
      background: transparent;
      color: var(--foreground);
      cursor: default;
      transition: background-color 120ms, color 120ms;
      &::before,
      &::after {
        content: "";
        position: absolute;
        inset: 50% auto auto 50%;
        translate: -50% -50%;
        box-sizing: border-box;
      }
      &:hover { background: color-mix(in oklch, var(--foreground) 10%, transparent); }
      &:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
    }
    /* minimize: a bar */
    & .window-minimize::before {
      width: 0.625rem;
      height: 1px;
      background: currentColor;
    }
    /* maximize: a box; restore (while maximized): two boxes */
    & .window-maximize::before {
      width: 0.625rem;
      height: 0.625rem;
      border: 1px solid currentColor;
      border-radius: 1px;
    }
    &[data-maximized] .window-maximize {
      &::before { translate: -40% -60%; width: 0.5rem; height: 0.5rem; }
      &::after {
        translate: -65% -35%;
        width: 0.5rem;
        height: 0.5rem;
        border: 1px solid currentColor;
        border-radius: 1px;
        background: var(--muted);
      }
    }
    /* close: an × */
    & .window-close {
      &::before,
      &::after {
        width: 0.75rem;
        height: 1px;
        background: currentColor;
        rotate: 45deg;
      }
      &::after { rotate: -45deg; }
    }
    /* Windows chrome: the × turns red with a white glyph. Stated through
       .window-controls > so it outranks the shared control hover (a light
       tint) - otherwise the white glyph landed on light grey. The other
       chromes style their own close button. */
    &:not([data-chrome="mac"], [data-chrome="linux"], [data-chrome="retro"]) .window-controls > .window-close:hover {
      background: oklch(0.58 0.21 27);
      color: oklch(0.99 0 0);
    }
    /* -- Toolbar: an app's menubar / buttons under the title bar -------- */
    & > .window-toolbar {
      display: flex;
      align-items: center;
      gap: 0.25rem;
      flex: none;
      min-height: 2.25rem;
      padding: 0.125rem 0.375rem;
      border-bottom: 1px solid var(--border);
      background: var(--background);
      overflow-x: auto;
    }
    /* -- Body / status bar -------------------------------------------- */
    & > .window-body {
      flex: 1;
      min-height: 0;
      padding: 1rem;
      overflow: auto;
      overscroll-behavior: contain;
    }
    & > .window-body[data-flush] { padding: 0; }
    & > .window-statusbar {
      display: flex;
      align-items: center;
      gap: 1rem;
      flex: none;
      padding: 0.25rem 0.75rem;
      border-top: 1px solid var(--border);
      background: var(--muted);
      color: var(--muted-foreground);
      font-size: 0.75rem;
    }
    /* -- Active / inactive ---------------------------------------------- */
    &:not([data-active]) {
      box-shadow: var(--shadow-sm);
      & > .window-titlebar { color: var(--muted-foreground); }
    }
    /* -- Maximized: fill the desktop; minimized: rolled up to the bar -- */
    &[data-maximized] {
      inset: 0;
      width: auto;
      height: auto;
      border-radius: 0;
      border-width: 0;
      resize: none;
      box-shadow: none;
    }
    &[data-minimized] {
      height: auto;
      min-height: 0;
      resize: none;
      & > :not(.window-titlebar) { display: none; }
      & > .window-titlebar { border-bottom: 0; }
    }
    &[data-dragging] { transition: none; }
    /* -- Chrome: macOS - traffic lights on the left, centred title ------- */
    &[data-chrome="mac"] {
      --_ctl: 1.25rem;
      & > .window-titlebar { padding-inline: 0.75rem; }
      & .window-controls {
        order: -1;
        align-self: center;
        gap: 0.5rem;
        margin-inline-end: 0.25rem;
      }
      & .window-controls > button {
        width: 0.75rem;
        height: 0.75rem;
        border-radius: 999px;
        color: oklch(0.3 0.05 30 / 0);
        &:hover { background: var(--_light); }
        &::before,
        &::after { scale: 0.7; }
      }
      /* the glyphs appear when the pointer is over the lights */
      & .window-controls:hover > button { color: oklch(0.3 0.05 30 / 0.8); }
      & .window-close { order: 1; --_light: oklch(0.68 0.2 25); }
      & .window-minimize { order: 2; --_light: oklch(0.82 0.16 85); }
      & .window-maximize { order: 3; --_light: oklch(0.74 0.17 145); }
      & .window-controls > button { background: var(--_light); }
      & .window-close:hover { color: oklch(0.3 0.05 30 / 0.8); }
      & .window-title { text-align: center; }
      /* the icon sits beside the centred title */
      & .window-icon { order: 1; }
      & .window-title { order: 0; }
      &[data-maximized] .window-maximize::after { background: var(--_light); }
      &:not([data-active]) .window-controls:not(:hover) > button { background: color-mix(in oklch, var(--muted-foreground) 35%, transparent); }
    }
    /* -- Chrome: Linux (GNOME) - round grey buttons on the right --------- */
    &[data-chrome="linux"] {
      --_ctl: 1.5rem;
      & > .window-titlebar { padding-inline-end: 0.5rem; }
      & .window-title { text-align: center; font-weight: 600; }
      & .window-controls { align-self: center; gap: 0.5rem; }
      & .window-controls > button {
        width: var(--_ctl);
        height: var(--_ctl);
        border-radius: 999px;
        background: color-mix(in oklch, var(--foreground) 9%, transparent);
        &::before,
        &::after { scale: 0.8; }
        &:hover { background: color-mix(in oklch, var(--foreground) 16%, transparent); }
      }
      & .window-close:hover { background: color-mix(in oklch, var(--foreground) 16%, transparent); color: var(--foreground); }
      &[data-maximized] .window-maximize::after { background: transparent; }
    }
    /* -- Chrome: retro - a bevelled 9x window with a gradient title ------ */
    &[data-chrome="retro"] {
      --_face: oklch(0.8 0 0);
      --_hi: oklch(1 0 0);
      --_lo: oklch(0.5 0 0);
      --_ctl: 1.125rem;
      padding: 3px;
      border: 0;
      border-radius: 0;
      background: var(--_face);
      color: oklch(0.15 0 0);
      box-shadow:
        inset -1px -1px 0 oklch(0.1 0 0), inset 1px 1px 0 var(--_face),
        inset -2px -2px 0 var(--_lo), inset 2px 2px 0 var(--_hi);
      & > .window-titlebar {
        height: 1.375rem;
        padding-inline: 0.25rem 0.125rem;
        gap: 0.25rem;
        border: 0;
        background: linear-gradient(90deg, oklch(0.3 0.16 264), oklch(0.62 0.12 240));
        color: oklch(1 0 0);
      }
      & .window-icon { color: inherit; }
      & .window-title { font-weight: 700; font-size: 0.75rem; }
      & .window-controls { align-self: center; gap: 2px; }
      & .window-controls > button {
        width: calc(var(--_ctl) + 2px);
        height: var(--_ctl);
        background: var(--_face);
        color: oklch(0.1 0 0);
        box-shadow:
          inset -1px -1px 0 oklch(0.1 0 0), inset 1px 1px 0 var(--_hi),
          inset -2px -2px 0 var(--_lo);
        &:hover { background: var(--_face); color: oklch(0.1 0 0); }
        &:active { box-shadow: inset 1px 1px 0 oklch(0.1 0 0), inset -1px -1px 0 var(--_hi), inset 2px 2px 0 var(--_lo); }
        &::before,
        &::after { scale: 0.75; }
      }
      & .window-close { margin-inline-start: 2px; }
      & .window-minimize::before { height: 2px; translate: -50% 150%; }
      & .window-maximize::before { border-top-width: 2px; }
      & .window-close::before,
      & .window-close::after { height: 2px; }
      &[data-maximized] .window-maximize::after { background: var(--_face); border-top-width: 2px; }
      & > .window-body {
        margin-top: 2px;
        background: oklch(1 0 0);
        box-shadow: inset 1px 1px 0 var(--_lo), inset -1px -1px 0 var(--_hi), inset 2px 2px 0 oklch(0.1 0 0);
      }
      & > .window-toolbar {
        margin-top: 2px;
        border: 0;
        background: var(--_face);
        color: oklch(0.15 0 0);
      }
      & > .window-statusbar {
        margin-top: 2px;
        border: 0;
        background: var(--_face);
        color: oklch(0.15 0 0);
        box-shadow: inset 1px 1px 0 var(--_lo), inset -1px -1px 0 var(--_hi);
      }
      &:not([data-active]) > .window-titlebar {
        background: linear-gradient(90deg, oklch(0.55 0 0), oklch(0.72 0 0));
        color: oklch(0.85 0 0);
      }
      &[data-maximized] { padding: 3px; }
    }
  }
  /* -- Accessibility -------------------------------------------- */
  @media (prefers-reduced-motion: reduce) {
    .window,
    .window .window-controls > button { transition: none; }
  }
  @media (prefers-contrast: more) {
    .window { border-color: var(--foreground); }
    .window > .window-titlebar { border-bottom-color: var(--foreground); }
    .window:not([data-active]) > .window-titlebar { color: var(--foreground); }
  }
  @media (forced-colors: active) {
    .window { border: 1px solid CanvasText; }
    .window[data-active] > .window-titlebar {
      background: Highlight;
      color: HighlightText;
      forced-color-adjust: none;
    }
    .window .window-controls > button::before,
    .window .window-controls > button::after { border-color: ButtonText; }
  }
}

§JS view file

// -- Window -----------------------------------------------------
// A desktop-style window on a non-modal <dialog>: the browser owns open /
// close (the × is a <form method="dialog"> submit, so it works without
// script) and the close event; this runtime adds what it cannot do - moving
// the window by its title bar (pointer capture, arrow keys), raising the
// clicked window to the front, maximize / minimize - plus the named-state
// API (AGENTS.md "State API") and the imperative df$.shadcn.win.
// Shared preamble (AGENTS.md "State API"); the implementation lives in core.js —
// build.ts rewrites this import into a df$.shadcn.shared binding in dist/.
import { defussGlobals, defussQuery, componentState, bindComponent } from '../../../shared/state-api.js';
const df$ = defussGlobals();
const dfDollar = defussQuery();
// VERIFIED: (verify's component types ratchet - tsc -p tsconfig.components.json) every type
// this file's API docs state - arguments, return values, event details - holds
// against its code: a wrong one is a new type error and fails the build.
/** A window's place inside its desktop, px. */
interface WindowPosition {
  /** from the desktop's left edge */
  x: number;
  /** from the desktop's top edge */
  y: number;
}
/** What create() takes - the shape the skill documents. */
interface WindowCreateOptions {
  /** the title bar text (default 'Untitled') */
  title?: string;
  /** a Lucide icon name for the title bar */
  icon?: string;
  /** the body: a node, or text */
  content?: Node | string;
  /** the body as markup (used when content is not a node) */
  html?: string;
  /** a status bar line */
  statusbar?: string;
  /** the window's id */
  id?: string;
  /** left edge: px, or a CSS length (default: cascaded from the windows before it) */
  x?: number | string;
  /** top edge: px, or a CSS length */
  y?: number | string;
  /** width: px, or a CSS length */
  width?: number | string;
  /** height: px, or a CSS length */
  height?: number | string;
  /** the look of the title bar */
  chrome?: 'windows' | 'mac' | 'linux' | 'retro';
  /** the native resize handle (default true) */
  resizable?: boolean;
  /** the desktop to open in: element, id or selector (default: the .window-desktop, else the body) */
  parent?: HTMLElement | string;
  /** open in front, active (default true) */
  focus?: boolean;
  /** a body without padding (an app inside) */
  flush?: boolean;
}
/** What window-focus carries. */
interface WindowFocusDetail {
  /** the title of the window now in front */
  title: string;
}
const windowStates = ['default', 'maximized', 'minimized', 'closed'];
/** setState() configs per state. */
export interface WindowStateConfigs {
  /** Open at its normal size (opens a closed window). */
  default: {
    /** move it: the left edge, px inside its desktop (with y) */
    x?: number;
    /** move it: the top edge, px inside its desktop (with x) */
    y?: number;
  };
  /** Fills the desktop. */
  maximized: {
    /** reported by getState() until it closes: the left edge set last, px */
    x?: number;
    /** reported by getState() until it closes: the top edge set last, px */
    y?: number;
  };
  /** Rolled up to its title bar. */
  minimized: {
    /** reported by getState() until it closes: the left edge set last, px */
    x?: number;
    /** reported by getState() until it closes: the top edge set last, px */
    y?: number;
  };
  /** Closed - also after the close button or close(); it reopens at its normal size. */
  closed: {};
}
/** Stacking order is shared by every window on the page - a counter, not state. */
let topZ = 10;
/** How much of a window must stay inside its desktop, so it can be grabbed back. */
const KEEP = 48;
const resolve = (target) =>
  typeof target === 'string'
    ? dfDollar('#' + CSS.escape(target)).get(0) ?? dfDollar(target).get(0)
    : target;
const titleOf = (w) => dfDollar(w).find('.window-title').get(0)?.textContent?.trim() ?? '';
/** The window's position inside its desktop, in px. */
const posOf = (w): WindowPosition => ({ x: w.offsetLeft, y: w.offsetTop });
/**
 * Moves a window, keeping it reachable: at least KEEP px of GRABBABLE title
 * bar stay inside the desktop - the controls don't count, so a window pushed
 * to an edge never shows only its buttons.
 */
function moveTo(w, x, y) {
  const parent = w.offsetParent;
  const bar = dfDollar(w).find('.window-titlebar').get(0);
  if (parent) {
    const ctl = dfDollar(w).find('.window-controls').get(0)?.offsetWidth ?? 0;
    const maxX = parent.clientWidth - KEEP - ctl;
    const minX = KEEP + ctl - w.offsetWidth;
    const maxY = parent.clientHeight - (bar?.offsetHeight ?? KEEP);
    x = Math.min(Math.max(x, minX), maxX);
    y = Math.min(Math.max(y, 0), Math.max(maxY, 0));
  }
  w.style.setProperty('--window-x', `${Math.round(x)}px`);
  w.style.setProperty('--window-y', `${Math.round(y)}px`);
  return { x: Math.round(x), y: Math.round(y) };
}
/** Raises a window above every other and marks it the active one. */
function raise(w) {
  if (!w.open) return;
  if (w.hasAttribute('data-active') && Number(w.style.zIndex) === topZ) return;
  topZ += 1;
  w.style.zIndex = String(topZ);
  dfDollar('.window[data-active]').toArray().forEach((o) => { if (o !== w) o.removeAttribute('data-active'); });
  w.setAttribute('data-active', '');
  // Fires when a window comes to the front - its title.
  w.dispatchEvent(new CustomEvent<WindowFocusDetail>('window-focus', { bubbles: true, detail: { title: titleOf(w) } }));
}
/**
 * show() runs the dialog focusing steps - it moves focus into the window
 * (onto the focusable title bar), which paints a focus ring on a window the
 * user never touched and pulls focus away from whatever opened it. Opening
 * leaves focus where it was; pressing into the window focuses as usual.
 */
function showQuietly(w) {
  const prev = document.activeElement as HTMLElement | null;
  w.show();
  if (prev && prev !== document.body && prev.isConnected && prev.focus) prev.focus({ preventScroll: true });
  else if (w.contains(document.activeElement)) (document.activeElement as HTMLElement).blur();
}
/** Hands "active" to the front-most open window left (after one closed). */
function activateTopmost() {
  const open = Array.from(dfDollar('.window[open]').toArray());
  if (!open.length) return;
  const top = open.reduce((a, b) => (Number(b.style.zIndex || 0) > Number(a.style.zIndex || 0) ? b : a));
  raise(top);
}
/** Maximize / minimize drop an inline size (from a native resize) and put it back after. */
function stashSize(w) {
  if (w._stash) return;
  w._stash = { width: w.style.width, height: w.style.height };
  w.style.width = '';
  w.style.height = '';
}
function restoreSize(w) {
  if (!w._stash) return;
  w.style.width = w._stash.width;
  w.style.height = w._stash.height;
  w._stash = null;
}
/**
 * The markup of a state, for render(): the attributes a state writes, applied
 * to a detached copy of the authored markup ('default' IS the authored
 * markup). The live element gets the same markup from triggerStateChange -
 * the e2e render round trip proves they agree.
 */
function applyMarkup(el, stateName) {
  const open = stateName !== 'closed';
  dfDollar(el).attr('open', open ? '' : null);
  dfDollar(el).attr('data-maximized', stateName === 'maximized' ? '' : null);
  dfDollar(el).attr('data-minimized', stateName === 'minimized' ? '' : null);
  dfDollar(el).find('.window-maximize').attr('aria-label', stateName === 'maximized' ? 'Restore' : 'Maximize');
  dfDollar(el).find('.window-minimize').attr('aria-label', stateName === 'minimized' ? 'Restore' : 'Minimize');
}
/**
 * UI side of setState. 'default' = open, normal size (opens a closed
 * window; `{ x, y }` moves it); 'maximized' fills the desktop; 'minimized'
 * rolls it up to its title bar; 'closed' closes the dialog.
 */
function triggerStateChange(w, stateName, config) {
  const maxBtn = dfDollar(w).find('.window-maximize').get(0);
  if (stateName !== 'closed' && !w.open) showQuietly(w);
  switch (stateName) {
    case 'default':
      w.removeAttribute('data-maximized');
      w.removeAttribute('data-minimized');
      restoreSize(w);
      if (config.x !== undefined && config.y !== undefined) moveTo(w, Number(config.x), Number(config.y));
      raise(w);
      break;
    case 'maximized':
      w.removeAttribute('data-minimized');
      stashSize(w);
      w.setAttribute('data-maximized', '');
      raise(w);
      break;
    case 'minimized':
      w.removeAttribute('data-maximized');
      stashSize(w);
      w.setAttribute('data-minimized', '');
      break;
    case 'closed':
      if (w.open) w.close(); // the close event hands "active" on
      // closed means closed: the size modes are not kept for the next open
      w.removeAttribute('data-maximized');
      w.removeAttribute('data-minimized');
      break;
  }
  if (maxBtn) maxBtn.setAttribute('aria-label', stateName === 'maximized' ? 'Restore' : 'Maximize');
  dfDollar(w).find('.window-minimize').get(0)?.setAttribute('aria-label', stateName === 'minimized' ? 'Restore' : 'Minimize');
}
/** Registry-level API; pass the .window element explicitly. Unknown names throw. */
export const windowApi = componentState<HTMLDialogElement>({
  component: 'window',
  states: windowStates,
  apply: (w, state) => {
    w.dataset.stateName = state.name;
    triggerStateChange(w, state.name, state.config);
  },
  read: (w, state) => {
    // the dialog is the truth: closed the moment it closes, before the
    // queued close event updates data-state-name
    const name = !w.open ? 'closed' : w.dataset.stateName || 'default';
    return { name, config: name === 'closed' ? {} : state.config };
  },
  markup: (el, state) => applyMarkup(el, state.name),
});
df$.windowApi = windowApi;
df$.windowStates = windowStates;
/** Title-bar dragging: pointer capture, so a fast drag never loses the window. */
function bindDrag(w, bar) {
  bar.addEventListener('pointerdown', (e) => {
    if (e.button !== 0 || e.target.closest('button, a, input, select, textarea')) return;
    raise(w);
    if (w.hasAttribute('data-maximized')) return;
    e.preventDefault();
    const start = posOf(w);
    const sx = e.clientX, sy = e.clientY;
    bar.setPointerCapture(e.pointerId);
    w.setAttribute('data-dragging', '');
    const onMove = (m) => moveTo(w, start.x + m.clientX - sx, start.y + m.clientY - sy);
    const onUp = () => {
      bar.removeEventListener('pointermove', onMove);
      bar.removeEventListener('pointerup', onUp);
      bar.removeEventListener('pointercancel', onUp);
      w.removeAttribute('data-dragging');
      // Fires after a window was dragged (or moved with the keyboard) - its position.
      w.dispatchEvent(new CustomEvent<WindowPosition>('window-move', { bubbles: true, detail: posOf(w) }));
    };
    bar.addEventListener('pointermove', onMove);
    bar.addEventListener('pointerup', onUp);
    bar.addEventListener('pointercancel', onUp);
  });
  // double-click the bar: maximize / restore, like every desktop
  bar.addEventListener('dblclick', (e) => {
    if (e.target.closest('button')) return;
    windowApi.setState(w, w.hasAttribute('data-maximized') ? 'default' : 'maximized', {});
  });
  // keyboard: the bar is focusable; arrows move (Shift = bigger steps)
  bar.addEventListener('keydown', (e) => {
    const step = e.shiftKey ? 64 : 16;
    const d = { ArrowLeft: [-step, 0], ArrowRight: [step, 0], ArrowUp: [0, -step], ArrowDown: [0, step] }[e.key];
    if (!d || w.hasAttribute('data-maximized') || e.target !== bar) return;
    e.preventDefault();
    const p = posOf(w);
    moveTo(w, p.x + d[0], p.y + d[1]);
    w.dispatchEvent(new CustomEvent<WindowPosition>('window-move', { bubbles: true, detail: posOf(w) }));
  });
}
function init() {
  dfDollar<HTMLDialogElement>('dialog.window:not([data-init])').toArray().forEach((w) => {
    w.dataset.init = '';
    const bar = dfDollar(w).find(':scope > .window-titlebar').get(0);
    if (bar) {
      if (!bar.hasAttribute('tabindex')) bar.tabIndex = 0;
      bindDrag(w, bar);
    }
    if (!w.hasAttribute('aria-labelledby') && !w.hasAttribute('aria-label')) {
      const title = dfDollar(w).find('.window-title').get(0);
      if (title) {
        if (!title.id) title.id = `window-title-${Math.random().toString(36).slice(2, 8)}`;
        w.setAttribute('aria-labelledby', title.id);
      }
    }
    // any press inside a window brings it to the front (capture: before
    // the content handles it); so does focus arriving by keyboard
    w.addEventListener('pointerdown', () => raise(w), true);
    w.addEventListener('focusin', () => raise(w));
    dfDollar(w).find('.window-maximize').get(0)?.addEventListener('click', () =>
      windowApi.setState(w, w.hasAttribute('data-maximized') ? 'default' : 'maximized', {}));
    // the × closes through the API too: the native form submit already
    // does it, but a page that cancels submits (a sandbox, a SPA) must not
    // strand the window open
    dfDollar(w).find('.window-close').get(0)?.addEventListener('click', (e) => {
      e.preventDefault();
      windowApi.setState(w, 'closed', {});
    });
    dfDollar(w).find('.window-minimize').get(0)?.addEventListener('click', () =>
      windowApi.setState(w, w.hasAttribute('data-minimized') ? 'default' : 'minimized', {}));
    // however it closed - the × (form method="dialog"), Escape-less
    // close(), the API - the state follows the dialog
    w.addEventListener('close', () => {
      // the event is queued: a window reopened meanwhile stays open
      if (w.open) return;
      w.dataset.stateName = 'closed';
      w.removeAttribute('data-active');
      w.removeAttribute('data-maximized');
      w.removeAttribute('data-minimized');
      activateTopmost();
    });
    // el.store + el.api (AGENTS.md "State through stores")
    bindComponent(w, windowApi);
    const initial = !w.open ? 'closed' : w.hasAttribute('data-maximized') ? 'maximized' : w.hasAttribute('data-minimized') ? 'minimized' : 'default';
    w.dataset.stateName = initial;
    // the buttons name what they do in the state the window starts in (an
    // authored maximized window's button restores it)
    dfDollar(w).find('.window-maximize').attr('aria-label', initial === 'maximized' ? 'Restore' : 'Maximize');
    dfDollar(w).find('.window-minimize').attr('aria-label', initial === 'minimized' ? 'Restore' : 'Minimize');
    if (w.open) {
      w.style.zIndex = String(++topZ);
      // the last authored open window starts active
      dfDollar('.window[data-active]').toArray().forEach((o) => o.removeAttribute('data-active'));
      w.setAttribute('data-active', '');
    }
  });
}
/**
 * Builds a window element from options - the shape the skill documents.
 * @param options - title, body, place, size, look and where it opens
 * @returns the new window (a <dialog class="window">), open unless focus is false
 */
function create(options: WindowCreateOptions = {}): HTMLDialogElement {
  const {
    title = 'Untitled', icon, content, html, statusbar, id,
    x, y, width, height, chrome, resizable = true, parent, focus = true, flush = false,
  } = options;
  const host = resolve(parent) ?? dfDollar('.window-desktop').get(0) ?? document.body;
  const w = document.createElement('dialog');
  w.className = 'window';
  if (id) w.id = id;
  if (chrome) w.dataset.chrome = chrome;
  if (resizable) w.setAttribute('data-resizable', '');
  const count = dfDollar(host).find(':scope > .window').toArray().length;
  w.style.setProperty('--window-x', typeof x === 'number' ? `${x}px` : x ?? `${24 + (count % 8) * 28}px`);
  w.style.setProperty('--window-y', typeof y === 'number' ? `${y}px` : y ?? `${24 + (count % 8) * 28}px`);
  if (width !== undefined) w.style.setProperty('--window-w', typeof width === 'number' ? `${width}px` : width);
  if (height !== undefined) w.style.setProperty('--window-h', typeof height === 'number' ? `${height}px` : height);
  const bar = document.createElement('header');
  bar.className = 'window-titlebar';
  if (icon) {
    const i = document.createElement('i');
    i.className = 'window-icon';
    i.setAttribute('data-lucide', icon);
    bar.append(i);
  }
  const h = document.createElement('h2');
  h.className = 'window-title';
  h.textContent = title;
  const controls = document.createElement('form');
  controls.method = 'dialog';
  controls.className = 'window-controls';
  for (const [cls, label, type] of [['window-minimize', 'Minimize', 'button'], ['window-maximize', 'Maximize', 'button'], ['window-close', 'Close', 'submit']] as const) {
    const b = document.createElement('button');
    b.type = type;
    b.className = cls;
    b.setAttribute('aria-label', label);
    controls.append(b);
  }
  bar.append(h, controls);
  const body = document.createElement('div');
  body.className = 'window-body';
  if (flush) body.setAttribute('data-flush', '');
  if (content instanceof Node) body.append(content);
  else if (typeof html === 'string') body.append(document.createRange().createContextualFragment(html));
  else if (content !== undefined) body.textContent = String(content);
  w.append(bar, body);
  if (statusbar !== undefined) {
    const s = document.createElement('footer');
    s.className = 'window-statusbar';
    s.textContent = String(statusbar);
    w.append(s);
  }
  host.append(w);
  init();
  showQuietly(w);
  if (focus) windowApi.setState(w, 'default', {});
  if (icon) globalThis.lucide?.createIcons?.();
  return w;
}
/**
 * Windows (open unless `all`) inside `scope` (default: the page).
 * @param scope - a desktop element, its id or a selector (default: the page)
 * @param all - true: closed windows too
 * @returns the windows, in document order
 */
const list = (scope?: HTMLElement | string, all: boolean = false): HTMLDialogElement[] =>
  dfDollar(resolve(scope) ?? document).find<HTMLDialogElement>(all ? '.window' : '.window[open]').toArray();
/**
 * Steps the open windows diagonally from the top-left, front-most last.
 * @param scope - a desktop element, its id or a selector (default: the page)
 * @param step - px between two windows (default 28)
 */
function cascade(scope?: HTMLElement | string, step: number = 28): void {
  list(scope)
    .sort((a, b) => Number(a.style.zIndex || 0) - Number(b.style.zIndex || 0))
    .forEach((w, i) => { windowApi.setState(w, 'default', {}); moveTo(w, 16 + i * step, 16 + i * step); });
}
/**
 * Lays the open windows side by side in a grid that fills their desktop.
 * @param scope - a desktop element, its id or a selector (default: the page)
 */
function tile(scope?: HTMLElement | string): void {
  const wins = list(scope);
  if (!wins.length) return;
  const cols = Math.ceil(Math.sqrt(wins.length));
  const rows = Math.ceil(wins.length / cols);
  wins.forEach((w, i) => {
    windowApi.setState(w, 'default', {});
    const p = w.offsetParent;
    if (!p) return;
    const cw = p.clientWidth / cols, ch = p.clientHeight / rows;
    w.style.width = '';
    w.style.height = '';
    w.style.setProperty('--window-w', `${Math.floor(cw)}px`);
    w.style.setProperty('--window-h', `${Math.floor(ch)}px`);
    moveTo(w, (i % cols) * cw, Math.floor(i / cols) * ch);
  });
}
// the imperative API: df$.shadcn.win.* - every method takes an element,
// an id or a selector
/** df$.shadcn.win - create, arrange and drive windows. */
export const windowActions = {
  create,
  /**
   * Open a window (closed, minimized or not shown yet) - config is the state's config.
   * @param target - the .window element, its id or a selector
   * @param config - where it opens: { x, y } px
   * @returns the window, null when the target matches none
   */
  open: (target: string | HTMLElement, config: { x?: number; y?: number } = {}): HTMLDialogElement | null => { const w = resolve(target); if (w) windowApi.setState(w, 'default', config); return w; },
  /**
   * Close it (the closed state).
   * @param target - the .window element, its id or a selector
   * @returns the window, null when the target matches none
   */
  close: (target: string | HTMLElement): HTMLDialogElement | null => { const w = resolve(target); if (w) windowApi.setState(w, 'closed', {}); return w; },
  /**
   * Bring it to the front (the active window).
   * @param target - the .window element, its id or a selector
   * @returns the window, null when the target matches none
   */
  focus: (target: string | HTMLElement): HTMLDialogElement | null => { const w = resolve(target); if (w?.open) raise(w); return w; },
  /**
   * Move it to x, y (px, inside its desktop).
   * @param target - the .window element, its id or a selector
   * @param x - the left edge, px
   * @param y - the top edge, px
   * @returns where it landed (kept reachable inside its desktop), null when the target matches none
   */
  move: (target: string | HTMLElement, x: number, y: number): WindowPosition | null => { const w = resolve(target); return w ? moveTo(w, x, y) : null; },
  /**
   * Size it: width (and height) as px numbers or CSS lengths.
   * @param target - the .window element, its id or a selector
   * @param width - px, or a CSS length
   * @param height - px, or a CSS length; omitted, the height stays
   * @returns the window, null when the target matches none
   */
  resize: (target: string | HTMLElement, width: number | string, height?: number | string): HTMLDialogElement | null => {
    const w = resolve(target);
    if (!w) return null;
    w.style.width = '';
    w.style.height = '';
    w.style.setProperty('--window-w', typeof width === 'number' ? `${width}px` : width);
    if (height !== undefined) w.style.setProperty('--window-h', typeof height === 'number' ? `${height}px` : height);
    return w;
  },
  /**
   * Fill the desktop.
   * @param target - the .window element, its id or a selector
   * @returns the window, null when the target matches none
   */
  maximize: (target: string | HTMLElement): HTMLDialogElement | null => { const w = resolve(target); if (w) windowApi.setState(w, 'maximized', {}); return w; },
  /**
   * Minimize it to the taskbar.
   * @param target - the .window element, its id or a selector
   * @returns the window, null when the target matches none
   */
  minimize: (target: string | HTMLElement): HTMLDialogElement | null => { const w = resolve(target); if (w) windowApi.setState(w, 'minimized', {}); return w; },
  /**
   * Back to its normal size and place.
   * @param target - the .window element, its id or a selector
   * @returns the window, null when the target matches none
   */
  restore: (target: string | HTMLElement): HTMLDialogElement | null => { const w = resolve(target); if (w) windowApi.setState(w, 'default', {}); return w; },
  /**
   * Maximize it, or restore it when it is maximized.
   * @param target - the .window element, its id or a selector
   * @returns the window, null when the target matches none
   */
  toggleMaximize: (target: string | HTMLElement): HTMLDialogElement | null => {
    const w = resolve(target);
    if (w) windowApi.setState(w, w.hasAttribute('data-maximized') ? 'default' : 'maximized', {});
    return w;
  },
  /**
   * The window in front.
   * @returns the active open window, undefined when none is open
   */
  active: (): HTMLDialogElement | undefined => dfDollar<HTMLDialogElement>('.window[open][data-active]').get(0),
  list,
  cascade,
  tile,
};
df$.win = windowActions;
init();
new MutationObserver(init).observe(document, { childList: true, subtree: true });

Comments, ideas or improvements? Edit this page's source on GitHub