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

i3 window frame

The workstation frame; an i3 bar with workspaces and Chinese i3status labels above the terminal and code-editor components as tiled, tabbed or floating windows behind i3 title bars.

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

Live variants

default

处理器 12% 内存储器 3.1G 局域网 up 电池 87%
~/theme — zsh
 ~/theme  main  ls -l ports
total 5
drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 alacritty
drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 gtk
-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 README.md
-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 verify.sh
lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 xresources -> ../tokens/
-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 evidence.tar.gz
 ~/theme  main  cat ports/gtk/port.json
cat: ports/gtk/port.json: No such file or directory
 ~/theme  main  npm run validate
title.js — editor
// Compose the window title of the focused container.
import { Container } from "./tree.js";
const MAX_LENGTH = 48;
export function title(container) {
  const name = container.name ?? "untitled…";
  let label = `${name} (${container.children.length})`;
  if (label.length > MAX_LENGTH) {
    label = label.slice(0, MAX_LENGTH) + "…";
  }
  return escape(label); /* escape() is deprecated */
}
const broken = 0x1G;
Markup
<j3w1-i3-window-frame id="example-i3-window-frame-default"><div class="i3-window-frame" role="region" aria-label="Workstation, workspace 1: theme, tiled">
  <div class="i3-window-frame-bar" role="group" aria-label="i3 bar">
    <div class="i3-window-frame-workspaces" role="tablist" aria-label="Workspaces">
      <button class="i3-window-frame-workspace" type="button" role="tab" aria-selected="true" tabindex="0" id="example-i3-window-frame-default-workspace-tab-0" aria-controls="example-i3-window-frame-default-workspace-panel-0">1:theme</button>
      <button class="i3-window-frame-workspace i3-window-frame-workspace-demo-target" type="button" role="tab" aria-selected="false" tabindex="-1" id="example-i3-window-frame-default-workspace-tab-1" aria-controls="example-i3-window-frame-default-workspace-panel-1">2:reference</button>
      <button class="i3-window-frame-workspace i3-window-frame-workspace-urgent" type="button" role="tab" aria-selected="false" tabindex="-1" id="example-i3-window-frame-default-workspace-tab-2" aria-controls="example-i3-window-frame-default-workspace-panel-2">3:ports<span class="i3-window-frame-urgent-mark">!<span class="sr-only"> urgent</span></span></button>
    </div>
    <div class="i3-window-frame-status" role="group" lang="zh" aria-label="状态">
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 处理器 12%</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 内存储器 3.1G</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 局域网 up</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 电池 87%</span>
      <time class="i3-window-frame-block i3-window-frame-clock" datetime="2026-09-06T14:32:07">09月06号 14时32分07秒</time>
    </div>
  </div>
  <section role="tabpanel" id="example-i3-window-frame-default-workspace-panel-0" aria-labelledby="example-i3-window-frame-default-workspace-tab-0"><div class="i3-window-frame-area">
    <div class="i3-window-frame-window i3-window-frame-focused" role="group" aria-label="Terminal window, focused" tabindex="0">
      <div class="i3-window-frame-title">~/theme — zsh</div>
<pre class="terminal terminal-transcript" role="log" aria-label="Shell transcript" tabindex="0"><span class="terminal-line"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> ls -l ports</span>
<span class="terminal-line">total 5</span>
<span class="terminal-line">drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 <span class="terminal-fg-5 terminal-bold">alacritty</span></span>
<span class="terminal-line">drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 <span class="terminal-fg-5 terminal-bold">gtk</span></span>
<span class="terminal-line">-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 <span class="terminal-sel">README.md</span></span>
<span class="terminal-line"><span class="terminal-sel">-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 </span><span class="terminal-sel terminal-fg-3">verify.sh</span></span>
<span class="terminal-line">lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 <span class="terminal-fg-7">xresources</span> -&gt; <span class="terminal-fg-2">../tokens/</span></span>
<span class="terminal-line">-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 <span class="terminal-fg-11">evidence.tar.gz</span></span>
<span class="terminal-line"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> cat ports/gtk/port.json</span>
<span class="terminal-line terminal-fg-5">cat: ports/gtk/port.json: No such file or directory</span>
<span class="terminal-line terminal-line-cursor"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> npm run validate<span class="terminal-cursor" aria-hidden="true"> </span></span></pre>
    </div>
    <div class="i3-window-frame-window" role="group" aria-label="Editor window" tabindex="0">
      <div class="i3-window-frame-title">title.js — editor</div>
<div class="code-editor" role="textbox" aria-multiline="true" aria-readonly="true" aria-label="title.js, read-only" tabindex="0">
  <pre class="code-editor-pre"><span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">1</span><span class="code-editor-text"><span class="code-editor-cm">// Compose the window title of the focused container.</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">2</span><span class="code-editor-text"><span class="code-editor-kw">import</span> <span class="code-editor-punct">{</span> <span class="code-editor-type">Container</span> <span class="code-editor-punct">}</span> <span class="code-editor-kw">from</span> <span class="code-editor-str">"./tree.js"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">3</span><span class="code-editor-text"><span class="code-editor-kw">const</span> <span class="code-editor-const">MAX_LENGTH</span> <span class="code-editor-op">=</span> <span class="code-editor-num">48</span><span class="code-editor-punct">;</span><span class="code-editor-ws" aria-hidden="true" data-whitespace="··"></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">4</span><span class="code-editor-text"><span class="code-editor-kw">export</span> <span class="code-editor-kw">function</span> <span class="code-editor-fn">title</span><span class="code-editor-punct code-editor-bracket">(</span><span class="code-editor-var">container</span><span class="code-editor-punct code-editor-bracket">)</span> <span class="code-editor-punct">{</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">5</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">const</span> <span class="code-editor-var">name</span> <span class="code-editor-op">=</span> <span class="code-editor-var">container</span><span class="code-editor-punct">.</span><span class="code-editor-prop">name</span> <span class="code-editor-op">??</span> <span class="code-editor-str">"untitled<span class="code-editor-esc">…</span>"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line code-editor-line-current"><span class="code-editor-ln" aria-hidden="true">6</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">let</span> <span class="code-editor-var">label</span> <span class="code-editor-op">=</span> <span class="code-editor-str">`${</span><span class="code-editor-var">name</span><span class="code-editor-str">} (${</span><span class="code-editor-var">container</span><span class="code-editor-punct">.</span><span class="code-editor-prop">children</span><span class="code-editor-punct">.</span><span class="code-editor-prop">length</span><span class="code-editor-str">})`</span><span class="code-editor-punct">;</span><span class="code-editor-caret" aria-hidden="true"></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">7</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">if</span> <span class="code-editor-punct">(</span><span class="code-editor-sel"><span class="code-editor-var">label</span><span class="code-editor-punct">.</span><span class="code-editor-prop">length</span> <span class="code-editor-op">&gt;</span> <span class="code-editor-const">MAX_LENGTH</span><span class="code-editor-punct">)</span> <span class="code-editor-punct">{</span></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">8</span><span class="code-editor-text"><span class="code-editor-sel"><span class="code-editor-indent">  </span><span class="code-editor-indent">  </span><span class="code-editor-var">label</span> <span class="code-editor-op">=</span> <span class="code-editor-var">label</span><span class="code-editor-punct">.</span><span class="code-editor-fn">slice</span><span class="code-editor-punct">(</span><span class="code-editor-num">0</span><span class="code-editor-punct">,</span> <span class="code-editor-const">MAX_LENGTH</span><span class="code-editor-punct">)</span></span> <span class="code-editor-op">+</span> <span class="code-editor-str">"…"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">9</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-punct">}</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">10</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">return</span> <span class="code-editor-fn code-editor-deprecated">escape</span><span class="code-editor-punct">(</span><span class="code-editor-var">label</span><span class="code-editor-punct">);</span> <span class="code-editor-cm">/* escape() is deprecated */</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">11</span><span class="code-editor-text"><span class="code-editor-punct">}</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">12</span><span class="code-editor-text"><span class="code-editor-kw">const</span> <span class="code-editor-var">broken</span> <span class="code-editor-op">=</span> <span class="code-editor-num">0x1</span><span class="code-editor-invalid">G</span><span class="code-editor-punct">;</span></span></span></pre>
</div>
    </div>
  </div></section>
<section role="tabpanel" id="example-i3-window-frame-default-workspace-panel-1" aria-labelledby="example-i3-window-frame-default-workspace-tab-1" hidden=""><p>Workspace 2 is empty.</p></section><section role="tabpanel" id="example-i3-window-frame-default-workspace-panel-2" aria-labelledby="example-i3-window-frame-default-workspace-tab-2" hidden=""><p>Workspace 3 is empty.</p></section></div></j3w1-i3-window-frame>

tabbed

处理器 12% 内存储器 3.1G 局域网 up 电池 87%
 ~/theme  main  ls -l ports
total 5
drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 alacritty
drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 gtk
-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 README.md
-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 verify.sh
lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 xresources -> ../tokens/
-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 evidence.tar.gz
 ~/theme  main  cat ports/gtk/port.json
cat: ports/gtk/port.json: No such file or directory
 ~/theme  main  npm run validate
Markup
<j3w1-i3-window-frame id="example-i3-window-frame-tabbed"><div class="i3-window-frame" role="region" aria-label="Workstation, workspace 1: theme, tabbed">
  <div class="i3-window-frame-bar" role="group" aria-label="i3 bar">
    <div class="i3-window-frame-workspaces" role="tablist" aria-label="Workspaces">
      <button class="i3-window-frame-workspace" type="button" role="tab" aria-selected="true" tabindex="0" id="example-i3-window-frame-tabbed-workspace-tab-0" aria-controls="example-i3-window-frame-tabbed-workspace-panel-0">1:theme</button>
      <button class="i3-window-frame-workspace i3-window-frame-workspace-demo-target" type="button" role="tab" aria-selected="false" tabindex="-1" id="example-i3-window-frame-tabbed-workspace-tab-1" aria-controls="example-i3-window-frame-tabbed-workspace-panel-1">2:reference</button>
      <button class="i3-window-frame-workspace i3-window-frame-workspace-urgent" type="button" role="tab" aria-selected="false" tabindex="-1" id="example-i3-window-frame-tabbed-workspace-tab-2" aria-controls="example-i3-window-frame-tabbed-workspace-panel-2">3:ports<span class="i3-window-frame-urgent-mark">!<span class="sr-only"> urgent</span></span></button>
    </div>
    <div class="i3-window-frame-status" role="group" lang="zh" aria-label="状态">
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 处理器 12%</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 内存储器 3.1G</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 局域网 up</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 电池 87%</span>
      <time class="i3-window-frame-block i3-window-frame-clock" datetime="2026-09-06T14:32:07">09月06号 14时32分07秒</time>
    </div>
  </div>
  <section role="tabpanel" id="example-i3-window-frame-tabbed-workspace-panel-0" aria-labelledby="example-i3-window-frame-tabbed-workspace-tab-0"><div class="i3-window-frame-area">
    <div class="i3-window-frame-container i3-window-frame-focused" role="group" aria-label="Tabbed container, focused" tabindex="0">
      <div class="i3-window-frame-tabs" role="tablist" aria-label="Windows in the container">
        <button class="i3-window-frame-tab" type="button" role="tab" id="example-i3-window-frame-tabbed-i3-tab-terminal" aria-selected="true" aria-controls="example-i3-window-frame-tabbed-i3-panel-terminal" tabindex="0">~/theme — zsh</button>
        <button class="i3-window-frame-tab" type="button" role="tab" id="example-i3-window-frame-tabbed-i3-tab-editor" aria-selected="false" aria-controls="example-i3-window-frame-tabbed-i3-panel-editor" tabindex="-1">title.js — editor</button>
      </div>
      <div class="i3-window-frame-panel" role="tabpanel" id="example-i3-window-frame-tabbed-i3-panel-terminal" aria-labelledby="example-i3-window-frame-tabbed-i3-tab-terminal">
<pre class="terminal terminal-transcript" role="log" aria-label="Shell transcript" tabindex="0"><span class="terminal-line"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> ls -l ports</span>
<span class="terminal-line">total 5</span>
<span class="terminal-line">drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 <span class="terminal-fg-5 terminal-bold">alacritty</span></span>
<span class="terminal-line">drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 <span class="terminal-fg-5 terminal-bold">gtk</span></span>
<span class="terminal-line">-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 <span class="terminal-sel">README.md</span></span>
<span class="terminal-line"><span class="terminal-sel">-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 </span><span class="terminal-sel terminal-fg-3">verify.sh</span></span>
<span class="terminal-line">lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 <span class="terminal-fg-7">xresources</span> -&gt; <span class="terminal-fg-2">../tokens/</span></span>
<span class="terminal-line">-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 <span class="terminal-fg-11">evidence.tar.gz</span></span>
<span class="terminal-line"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> cat ports/gtk/port.json</span>
<span class="terminal-line terminal-fg-5">cat: ports/gtk/port.json: No such file or directory</span>
<span class="terminal-line terminal-line-cursor"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> npm run validate<span class="terminal-cursor" aria-hidden="true"> </span></span></pre>
      </div>
      <div class="i3-window-frame-panel" role="tabpanel" id="example-i3-window-frame-tabbed-i3-panel-editor" aria-labelledby="example-i3-window-frame-tabbed-i3-tab-editor" hidden="">
<div class="code-editor" role="textbox" aria-multiline="true" aria-readonly="true" aria-label="title.js, read-only" tabindex="0">
  <pre class="code-editor-pre"><span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">1</span><span class="code-editor-text"><span class="code-editor-cm">// Compose the window title of the focused container.</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">2</span><span class="code-editor-text"><span class="code-editor-kw">import</span> <span class="code-editor-punct">{</span> <span class="code-editor-type">Container</span> <span class="code-editor-punct">}</span> <span class="code-editor-kw">from</span> <span class="code-editor-str">"./tree.js"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">3</span><span class="code-editor-text"><span class="code-editor-kw">const</span> <span class="code-editor-const">MAX_LENGTH</span> <span class="code-editor-op">=</span> <span class="code-editor-num">48</span><span class="code-editor-punct">;</span><span class="code-editor-ws" aria-hidden="true" data-whitespace="··"></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">4</span><span class="code-editor-text"><span class="code-editor-kw">export</span> <span class="code-editor-kw">function</span> <span class="code-editor-fn">title</span><span class="code-editor-punct code-editor-bracket">(</span><span class="code-editor-var">container</span><span class="code-editor-punct code-editor-bracket">)</span> <span class="code-editor-punct">{</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">5</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">const</span> <span class="code-editor-var">name</span> <span class="code-editor-op">=</span> <span class="code-editor-var">container</span><span class="code-editor-punct">.</span><span class="code-editor-prop">name</span> <span class="code-editor-op">??</span> <span class="code-editor-str">"untitled<span class="code-editor-esc">…</span>"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line code-editor-line-current"><span class="code-editor-ln" aria-hidden="true">6</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">let</span> <span class="code-editor-var">label</span> <span class="code-editor-op">=</span> <span class="code-editor-str">`${</span><span class="code-editor-var">name</span><span class="code-editor-str">} (${</span><span class="code-editor-var">container</span><span class="code-editor-punct">.</span><span class="code-editor-prop">children</span><span class="code-editor-punct">.</span><span class="code-editor-prop">length</span><span class="code-editor-str">})`</span><span class="code-editor-punct">;</span><span class="code-editor-caret" aria-hidden="true"></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">7</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">if</span> <span class="code-editor-punct">(</span><span class="code-editor-sel"><span class="code-editor-var">label</span><span class="code-editor-punct">.</span><span class="code-editor-prop">length</span> <span class="code-editor-op">&gt;</span> <span class="code-editor-const">MAX_LENGTH</span><span class="code-editor-punct">)</span> <span class="code-editor-punct">{</span></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">8</span><span class="code-editor-text"><span class="code-editor-sel"><span class="code-editor-indent">  </span><span class="code-editor-indent">  </span><span class="code-editor-var">label</span> <span class="code-editor-op">=</span> <span class="code-editor-var">label</span><span class="code-editor-punct">.</span><span class="code-editor-fn">slice</span><span class="code-editor-punct">(</span><span class="code-editor-num">0</span><span class="code-editor-punct">,</span> <span class="code-editor-const">MAX_LENGTH</span><span class="code-editor-punct">)</span></span> <span class="code-editor-op">+</span> <span class="code-editor-str">"…"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">9</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-punct">}</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">10</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">return</span> <span class="code-editor-fn code-editor-deprecated">escape</span><span class="code-editor-punct">(</span><span class="code-editor-var">label</span><span class="code-editor-punct">);</span> <span class="code-editor-cm">/* escape() is deprecated */</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">11</span><span class="code-editor-text"><span class="code-editor-punct">}</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">12</span><span class="code-editor-text"><span class="code-editor-kw">const</span> <span class="code-editor-var">broken</span> <span class="code-editor-op">=</span> <span class="code-editor-num">0x1</span><span class="code-editor-invalid">G</span><span class="code-editor-punct">;</span></span></span></pre>
</div>
      </div>
    </div>
  </div></section>
<section role="tabpanel" id="example-i3-window-frame-tabbed-workspace-panel-1" aria-labelledby="example-i3-window-frame-tabbed-workspace-tab-1" hidden=""><p>Workspace 2 is empty.</p></section><section role="tabpanel" id="example-i3-window-frame-tabbed-workspace-panel-2" aria-labelledby="example-i3-window-frame-tabbed-workspace-tab-2" hidden=""><p>Workspace 3 is empty.</p></section></div></j3w1-i3-window-frame>

floating

处理器 12% 内存储器 3.1G 局域网 up 电池 87%
~/theme — zsh
 ~/theme  main  ls -l ports
total 5
drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 alacritty
drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 gtk
-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 README.md
-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 verify.sh
lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 xresources -> ../tokens/
-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 evidence.tar.gz
 ~/theme  main  cat ports/gtk/port.json
cat: ports/gtk/port.json: No such file or directory
 ~/theme  main  npm run validate
title.js — editor
// Compose the window title of the focused container.
import { Container } from "./tree.js";
const MAX_LENGTH = 48;
export function title(container) {
  const name = container.name ?? "untitled…";
  let label = `${name} (${container.children.length})`;
  if (label.length > MAX_LENGTH) {
    label = label.slice(0, MAX_LENGTH) + "…";
  }
  return escape(label); /* escape() is deprecated */
}
const broken = 0x1G;
Markup
<j3w1-i3-window-frame id="example-i3-window-frame-floating"><div class="i3-window-frame" role="region" aria-label="Workstation, workspace 1: theme, with a floating window">
  <div class="i3-window-frame-bar" role="group" aria-label="i3 bar">
    <div class="i3-window-frame-workspaces" role="tablist" aria-label="Workspaces">
      <button class="i3-window-frame-workspace" type="button" role="tab" aria-selected="true" tabindex="0" id="example-i3-window-frame-floating-workspace-tab-0" aria-controls="example-i3-window-frame-floating-workspace-panel-0">1:theme</button>
      <button class="i3-window-frame-workspace i3-window-frame-workspace-demo-target" type="button" role="tab" aria-selected="false" tabindex="-1" id="example-i3-window-frame-floating-workspace-tab-1" aria-controls="example-i3-window-frame-floating-workspace-panel-1">2:reference</button>
      <button class="i3-window-frame-workspace i3-window-frame-workspace-urgent" type="button" role="tab" aria-selected="false" tabindex="-1" id="example-i3-window-frame-floating-workspace-tab-2" aria-controls="example-i3-window-frame-floating-workspace-panel-2">3:ports<span class="i3-window-frame-urgent-mark">!<span class="sr-only"> urgent</span></span></button>
    </div>
    <div class="i3-window-frame-status" role="group" lang="zh" aria-label="状态">
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 处理器 12%</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 内存储器 3.1G</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 局域网 up</span>
      <span class="i3-window-frame-block"><span class="i3-window-frame-glyph" aria-hidden="true"></span> 电池 87%</span>
      <time class="i3-window-frame-block i3-window-frame-clock" datetime="2026-09-06T14:32:07">09月06号 14时32分07秒</time>
    </div>
  </div>
  <section role="tabpanel" id="example-i3-window-frame-floating-workspace-panel-0" aria-labelledby="example-i3-window-frame-floating-workspace-tab-0"><div class="i3-window-frame-area i3-window-frame-area-floating">
    <div class="i3-window-frame-window" role="group" aria-label="Terminal window" tabindex="0">
      <div class="i3-window-frame-title">~/theme — zsh</div>
<pre class="terminal terminal-transcript" role="log" aria-label="Shell transcript" tabindex="0"><span class="terminal-line"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> ls -l ports</span>
<span class="terminal-line">total 5</span>
<span class="terminal-line">drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 <span class="terminal-fg-5 terminal-bold">alacritty</span></span>
<span class="terminal-line">drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 <span class="terminal-fg-5 terminal-bold">gtk</span></span>
<span class="terminal-line">-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 <span class="terminal-sel">README.md</span></span>
<span class="terminal-line"><span class="terminal-sel">-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 </span><span class="terminal-sel terminal-fg-3">verify.sh</span></span>
<span class="terminal-line">lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 <span class="terminal-fg-7">xresources</span> -&gt; <span class="terminal-fg-2">../tokens/</span></span>
<span class="terminal-line">-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 <span class="terminal-fg-11">evidence.tar.gz</span></span>
<span class="terminal-line"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> cat ports/gtk/port.json</span>
<span class="terminal-line terminal-fg-5">cat: ports/gtk/port.json: No such file or directory</span>
<span class="terminal-line terminal-line-cursor"><span class="terminal-prompt"><span class="terminal-prompt-path"> ~/theme </span><span class="terminal-prompt-arrow terminal-prompt-arrow-path" aria-hidden="true">▶</span><span class="terminal-prompt-branch"> main </span><span class="terminal-prompt-arrow terminal-prompt-arrow-branch" aria-hidden="true">▶</span></span> npm run validate<span class="terminal-cursor" aria-hidden="true"> </span></span></pre>
    </div>
    <div class="i3-window-frame-window i3-window-frame-floating i3-window-frame-focused" role="group" aria-label="Editor window, floating, focused" tabindex="0">
      <div class="i3-window-frame-title">title.js — editor</div>
<div class="code-editor" role="textbox" aria-multiline="true" aria-readonly="true" aria-label="title.js, read-only" tabindex="0">
  <pre class="code-editor-pre"><span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">1</span><span class="code-editor-text"><span class="code-editor-cm">// Compose the window title of the focused container.</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">2</span><span class="code-editor-text"><span class="code-editor-kw">import</span> <span class="code-editor-punct">{</span> <span class="code-editor-type">Container</span> <span class="code-editor-punct">}</span> <span class="code-editor-kw">from</span> <span class="code-editor-str">"./tree.js"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">3</span><span class="code-editor-text"><span class="code-editor-kw">const</span> <span class="code-editor-const">MAX_LENGTH</span> <span class="code-editor-op">=</span> <span class="code-editor-num">48</span><span class="code-editor-punct">;</span><span class="code-editor-ws" aria-hidden="true" data-whitespace="··"></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">4</span><span class="code-editor-text"><span class="code-editor-kw">export</span> <span class="code-editor-kw">function</span> <span class="code-editor-fn">title</span><span class="code-editor-punct code-editor-bracket">(</span><span class="code-editor-var">container</span><span class="code-editor-punct code-editor-bracket">)</span> <span class="code-editor-punct">{</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">5</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">const</span> <span class="code-editor-var">name</span> <span class="code-editor-op">=</span> <span class="code-editor-var">container</span><span class="code-editor-punct">.</span><span class="code-editor-prop">name</span> <span class="code-editor-op">??</span> <span class="code-editor-str">"untitled<span class="code-editor-esc">…</span>"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line code-editor-line-current"><span class="code-editor-ln" aria-hidden="true">6</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">let</span> <span class="code-editor-var">label</span> <span class="code-editor-op">=</span> <span class="code-editor-str">`${</span><span class="code-editor-var">name</span><span class="code-editor-str">} (${</span><span class="code-editor-var">container</span><span class="code-editor-punct">.</span><span class="code-editor-prop">children</span><span class="code-editor-punct">.</span><span class="code-editor-prop">length</span><span class="code-editor-str">})`</span><span class="code-editor-punct">;</span><span class="code-editor-caret" aria-hidden="true"></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">7</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">if</span> <span class="code-editor-punct">(</span><span class="code-editor-sel"><span class="code-editor-var">label</span><span class="code-editor-punct">.</span><span class="code-editor-prop">length</span> <span class="code-editor-op">&gt;</span> <span class="code-editor-const">MAX_LENGTH</span><span class="code-editor-punct">)</span> <span class="code-editor-punct">{</span></span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">8</span><span class="code-editor-text"><span class="code-editor-sel"><span class="code-editor-indent">  </span><span class="code-editor-indent">  </span><span class="code-editor-var">label</span> <span class="code-editor-op">=</span> <span class="code-editor-var">label</span><span class="code-editor-punct">.</span><span class="code-editor-fn">slice</span><span class="code-editor-punct">(</span><span class="code-editor-num">0</span><span class="code-editor-punct">,</span> <span class="code-editor-const">MAX_LENGTH</span><span class="code-editor-punct">)</span></span> <span class="code-editor-op">+</span> <span class="code-editor-str">"…"</span><span class="code-editor-punct">;</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">9</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-punct">}</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">10</span><span class="code-editor-text"><span class="code-editor-indent">  </span><span class="code-editor-kw">return</span> <span class="code-editor-fn code-editor-deprecated">escape</span><span class="code-editor-punct">(</span><span class="code-editor-var">label</span><span class="code-editor-punct">);</span> <span class="code-editor-cm">/* escape() is deprecated */</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">11</span><span class="code-editor-text"><span class="code-editor-punct">}</span></span></span>
<span class="code-editor-line"><span class="code-editor-ln" aria-hidden="true">12</span><span class="code-editor-text"><span class="code-editor-kw">const</span> <span class="code-editor-var">broken</span> <span class="code-editor-op">=</span> <span class="code-editor-num">0x1</span><span class="code-editor-invalid">G</span><span class="code-editor-punct">;</span></span></span></pre>
</div>
    </div>
  </div></section>
<section role="tabpanel" id="example-i3-window-frame-floating-workspace-panel-1" aria-labelledby="example-i3-window-frame-floating-workspace-tab-1" hidden=""><p>Workspace 2 is empty.</p></section><section role="tabpanel" id="example-i3-window-frame-floating-workspace-panel-2" aria-labelledby="example-i3-window-frame-floating-workspace-tab-2" hidden=""><p>Workspace 3 is empty.</p></section></div></j3w1-i3-window-frame>

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

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 i3-window-frame --out ./vendor/j3w1/i3-window-frame

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.

methods

NameType / signatureMeaning
refresh(): voidReconnect behavior after replacing native child structure.
focus(options?: FocusOptions): voidFocus the first usable native control.

events

NameType / signatureMeaning
j3w1-window-actionCustomEventRequest a host window action; the browser component does not control OS windows.

Dependencies and verification

Registered components: none. Style dependencies: terminal, code-editor, tabs.

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

i3 window frame i3-window-frame

  • Family: Composed specimens
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Native control: region landmark; a group for the bar holding a tablist of workspaces (aria-selected on the visible one) and a labelled status group; each window a focusable named group, or a tablist and tabpanels in the tabbed variant; the clients keep their own roles (log, textbox) — APG pattern
  • specified
  • demonstrated

The workstation frame; an i3 bar with workspaces and Chinese i3status labels above the terminal and code-editor components as tiled, tabbed or floating windows behind i3 title bars.

Report an issue with this component

Tokens

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

PartRoleValueUse
root.bgcolor.surface.desktopobserveduse#000000Behind every window.
root.bordercolor.border.defaultapproveduse#482b2bD-041 border.default: color.primitive.modern.divider.
bar.bgcolor.surface.chromeapproveduse#000000D-041 surface.chrome: color.primitive.ink.0.
bar.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.
bar.rulecolor.border.dividerapproveduse#482b2bD-041 border.divider: color.primitive.modern.divider.
workspace.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.
workspace.selected-bgcolor.interaction.selection.bgapproveduse#531310Selected row, tab, workspace; D-027 recessed the fill, leaving the 2px indicator and the check to carry selection.
workspace.selected-textcolor.interaction.selection.textobserveduse#f4eeeeText on the selection.
workspace.bg-hovercolor.interaction.hover.bgapproveduse#1c1010D-041 interaction.hover.bg: color.primitive.modern.hover.
workspace.ringcolor.interaction.focus.ringobserveduse#e539351px dashed focus ring on controls and rows.
workspace.ring-on-selectioncolor.interaction.focus.ringobserveduse#e539351px dashed focus ring on controls and rows.
workspace.urgent-bgcolor.status.danger.fillobserveduse#dc282eDanger fill.
workspace.urgent-textcolor.status.danger.on-fillobserveduse#f9faf9Text on the danger fill (4.58:1).
status.separatorcolor.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.
status.glyphcolor.icon.decorativeapproveduse#986f72D-041 icon.decorative: color.primitive.modern.control.
clock.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.
area.bgcolor.surface.desktopobserveduse#000000Behind every window.
window.bgcolor.surface.canvasapproveduse#000000Page and terminal background.
window.bordercolor.border.defaultapproveduse#482b2bD-041 border.default: color.primitive.modern.divider.
window.border-focusedcolor.border.activeobserveduse#e53935Active or focused control border.
window.ringcolor.interaction.focus.ring-containerobserveduse#ffa2a7Focus colour for containers and explicitly mapped filled controls (D-015); component rules determine ring geometry.
title.bgcolor.surface.chromeapproveduse#000000D-041 surface.chrome: color.primitive.ink.0.
title.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.
title.bg-focusedcolor.surface.chrome-altapproveduse#140b0bD-041 surface.chrome-alt: color.primitive.modern.raised.
title.text-focusedcolor.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.
tab.indicatorcolor.border.selected-indicatorobserveduse#e539352px indicator bar on the selected tab or nav item.
tab.indicator-inactivecolor.border.selected-indicator-inactiveobserveduse#9e231fIndicator bar when the container is not focused.
floating.bordercolor.border.overlayapproveduse#c81a1aD-041 owner correction: red control and floating-frame borders, distinct from rose text.
floating.shadowshadow.floatingobserveduse0px 6px 22px 0px rgb(0 0 0 / 55%)The only shadow: the i3 floating window.
terminal.bgcolor.terminal.bgapproveduse#000000D-041 terminal.bg: color.primitive.ink.0.
terminal.textcolor.terminal.fgapproveduse#ffa2a7D-041: bright rose terminal text for readable black-background shells.
editor.bgcolor.code.bgapproveduse#000000D-041 code.bg: color.primitive.ink.0.

State matrix

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

StateTiledTabbedFloating
default
处理器 12% 内存储器 3.1G 局域网 up 电池 87%
~/theme — zsh
 ~/theme  main  ls -l ports
total 5
drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 alacritty
drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 gtk
-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 README.md
-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 verify.sh
lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 xresources -> ../tokens/
-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 evidence.tar.gz
 ~/theme  main  cat ports/gtk/port.json
cat: ports/gtk/port.json: No such file or directory
 ~/theme  main  npm run validate
title.js — editor
// Compose the window title of the focused container.
import { Container } from "./tree.js";
const MAX_LENGTH = 48;
export function title(container) {
  const name = container.name ?? "untitled…";
  let label = `${name} (${container.children.length})`;
  if (label.length > MAX_LENGTH) {
    label = label.slice(0, MAX_LENGTH) + "…";
  }
  return escape(label); /* escape() is deprecated */
}
const broken = 0x1G;
处理器 12% 内存储器 3.1G 局域网 up 电池 87%
 ~/theme  main  ls -l ports
total 5
drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 alacritty
drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 gtk
-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 README.md
-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 verify.sh
lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 xresources -> ../tokens/
-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 evidence.tar.gz
 ~/theme  main  cat ports/gtk/port.json
cat: ports/gtk/port.json: No such file or directory
 ~/theme  main  npm run validate
处理器 12% 内存储器 3.1G 局域网 up 电池 87%
~/theme — zsh
 ~/theme  main  ls -l ports
total 5
drwxr-xr-x  2 j3w1 j3w1  4096 Sep  6 09:12 alacritty
drwx------  2 j3w1 j3w1  4096 Sep  6 09:12 gtk
-rw-r--r--  1 j3w1 j3w1  1180 Sep  6 09:12 README.md
-rwxr-xr-x  1 j3w1 j3w1   512 Sep  6 09:12 verify.sh
lrwxrwxrwx  1 j3w1 j3w1    11 Sep  6 09:12 xresources -> ../tokens/
-rw-r--r--  1 j3w1 j3w1 20480 Sep  6 09:12 evidence.tar.gz
 ~/theme  main  cat ports/gtk/port.json
cat: ports/gtk/port.json: No such file or directory
 ~/theme  main  npm run validate
title.js — editor
// Compose the window title of the focused container.
import { Container } from "./tree.js";
const MAX_LENGTH = 48;
export function title(container) {
  const name = container.name ?? "untitled…";
  let label = `${name} (${container.children.length})`;
  if (label.length > MAX_LENGTH) {
    label = label.slice(0, MAX_LENGTH) + "…";
  }
  return escape(label); /* escape() is deprecated */
}
const broken = 0x1G;
focus-visible
selected
container-inactive
error

Purpose

The frame the palette was tuned in. It proves that the terminal and code-editor components sit in window chrome drawn from the same roles, and it records the workstation’s geometry as reference metrics. A specimen of composition, not a desktop: only i3 and sway ports draw this frame.

Anatomy

Parts as listed in the anatomy.

States

StateVisualNon-colour channel
defaultterminal window focused: color.border.active frame, bright title; editor at rest; workspace 1 filledthe title text; aria-selected
focus-visible2px color.interaction.focus.ring-container ring at −3px inside the focused window or container; the client draws no second ringthe ring
selectedworkspace 2 takes the selection fill with color.interaction.selection.text, 1px dashed color.interaction.focus.ring at −2px when focused; workspace 1 at restaria-selected
container-inactiveno window focused: every frame color.border.default, every title color.text.muted on color.surface.chrome, tab indicator color.border.selected-indicator-inactive, no caretlightness drop; no caret
errorworkspace 3 urgent: color.status.danger.fill with color.status.danger.on-fill and a trailing !the ! mark; “urgent” read to assistive technology

The clients keep their own states (the terminal’s busy cursor, the editor’s selection and read-only gutter); only the states the frame adds are declared here.

Keyboard

As in the key table. A window group can hold focus itself, as i3 focuses a container. Nothing traps focus.

Accessibility

The region names its workspace and layout. The workspace tablist is named; the status group is lang="zh"; its Nerd Font glyphs are aria-hidden, so only the labels are read. Every window is a named group; the focused and the floating window say so in their names. Urgency carries the ! mark and a visually hidden “urgent”. Text meets 4.5:1; frames, the ring and the urgent fill 3:1.

Portability

The geometry is recorded so a port of the i3 configuration matches the workstation; any other application keeps its own window manager, bar and gaps.

Non-examples

Rounded corners or a title-bar gradient. A focused window that glows or blurs its neighbours. A shadow under a tiled window. 14/−2 gaps forced into an unrelated application. A red underline instead of the selection fill for the workspace. Traffic-light buttons in the title bar. A translucent bar.

Contrast report

21 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
i3-window-frame default textdefaulttextcolor.text.muted #d4868bcolor.surface.chrome #0000007.584.5pass
i3-window-frame focus-visible textfocus-visibletextcolor.text.bright #ffa2a7color.surface.chrome-alt #140b0b10.144.5pass
i3-window-frame focus-visible outlinefocus-visibleuicolor.interaction.focus.ring-container #ffa2a7color.surface.chrome-alt #140b0b10.143pass
i3-window-frame selected textselectedtextcolor.interaction.selection.text #f4eeeecolor.interaction.selection.bg #53131012.474.5pass
i3-window-frame container-inactive textcontainer-inactivetextcolor.text.muted #d4868bcolor.surface.chrome #0000007.584.5pass
i3-window-frame error texterrortextcolor.status.danger.on-fill #f9faf9color.status.danger.fill #dc282e4.584.5pass
ring on a selected workspace when focusedselecteduicolor.interaction.focus.ring #e53935color.interaction.selection.bg #5313103.383pass
workspace names and status text on the bar—textcolor.text.default #e99499color.surface.chrome #0000009.164.5pass
clock on the bar—textcolor.text.bright #ffa2a7color.surface.chrome #00000010.984.5pass
focused title—textcolor.text.bright #ffa2a7color.surface.chrome-alt #140b0b10.144.5pass
focused window frame on the desktop—uicolor.border.active #e53935color.surface.desktop #0000004.973pass
floating window frame on the desktop—uicolor.border.overlay #c81a1acolor.surface.desktop #0000003.623pass
container ring on the window surfacefocus-visibleuicolor.interaction.focus.ring-container #ffa2a7color.surface.canvas #00000010.983pass
ring on a workspace or tab—uicolor.interaction.focus.ring #e53935color.surface.chrome #0000004.973pass
visible-tab indicator on the title row—uicolor.border.selected-indicator #e53935color.surface.chrome #0000004.973pass
urgent fill against the barerroruicolor.status.danger.fill #dc282ecolor.surface.chrome #0000004.393pass
visible-workspace fill against the bar—uicolor.interaction.selection.bg #531310color.surface.chrome #0000001.471pass
inactive tab indicatorcontainer-inactiveuicolor.border.selected-indicator-inactive #9e231fcolor.surface.chrome #0000002.711pass
unfocused window frames (decorative)—uicolor.border.default #482b2bcolor.surface.desktop #0000001.661pass
status block separators (decorative)—uicolor.text.muted #d4868bcolor.surface.chrome #0000007.581pass
status glyphs (decorative)—uicolor.icon.decorative #986f72color.surface.chrome #0000004.851pass

Keys

KeyAction
Tab / Shift+TabThe workspace tablist (its selected tab is the stop), then each window group, then the client inside it; in the tabbed variant the tab list, then the visible panel's client.
Arrow keysMove between workspaces in the bar and between tabs in a tabbed container; inside a client the client's own contract applies.
Enter / SpaceShows the workspace or tab under focus.
Mod+h j k l, Mod+1..9The window manager's own bindings move focus and switch workspaces on the workstation; the specimen documents them and does not reimplement them.

For agents

Component JSON ·Implementation brief ·Build a task kit ·

Related: terminal code-editor tabs

Stress fixtures: FX-STATE-MATRIX FX-320 FX-360 FX-ZOOM-200 FX-RM FX-HC FX-I18N FX-RTL FX-DENSITY