j3w1 / i3 window frameVue · HTML · React · Astro

J3W1 / DESIGN SYSTEM

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 · 1.1.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;

<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">··</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

<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">··</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;

<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">··</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@1.1.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@1.1.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

Purpose

The frame the palette was tuned in: an i3 bar, tiled windows with 1px pixel borders, 14/−2 gaps, a tabbed container and one floating window. It proves that the terminal and code-editor components sit inside window chrome drawn from the same roles, and it records the workstation’s geometry as reference metrics. It is a specimen of composition, not a desktop.

Anatomy

The region on color.surface.desktop; the 28px bar on color.surface.chrome with the workspace tablist (the visible workspace on color.interaction.selection.bg) and the i3status group in Chinese with its clock in color.text.bright; the workspace grid with the reference gaps; each window a focusable group behind a 1px color.border.default frame, color.border.active when focused, with a 23px title bar in color.text.muted on color.surface.chrome that turns color.text.bright on color.surface.chrome-alt when focused; the terminal or code-editor as the client with its own boundary given up to the frame. Tabbed: the titles form a tablist whose visible tab carries the 2px color.border.selected-indicator. Floating: the editor sits above the terminal behind color.border.overlay with shadow.floating, the only shadow in the theme.

States

StateVisualNon-colour channel
defaultthe terminal window focused: color.border.active frame and the bright title; the editor at rest; workspace 1 filledthe title text; aria-selected
focus-visiblethe 2px 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; workspace 1 drops to restaria-selected
container-inactiveno window has focus: every frame color.border.default, every title color.text.muted on color.surface.chrome, the tab indicator color.border.selected-indicator-inactive, no caretlightness drop; no caret
errorworkspace 3 is 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); this specimen declares only the states the frame adds around them.

Keyboard

The workspace tablist is one stop with arrow movement; Enter or Space shows a workspace. Each window is a focusable group so the frame itself can hold focus, as i3 focuses a container; Tab then enters the client, whose own contract applies (the terminal log, the read-only editor textbox). In the tabbed variant the tab list is one stop and only the visible panel’s client follows. Mod+h j k l and Mod+1..9 belong to the window manager and are documented, not reimplemented. Nothing traps focus.

Accessibility

The region names its workspace and layout. The bar is a group holding a named tablist and a status group in lang="zh", whose Nerd Font glyphs are aria-hidden so only the labels are read. Every window is a named group; the focused one says so in its name and the floating one too. Urgency carries the ! mark and a visually hidden “urgent”. Contrast: workspace names 8.60:1 and the clock 10.31:1 on the bar, focused titles 10.01:1, rest titles 5.77:1, the focused frame 4.97:1 and the ring 10.37:1 on the window surface, the urgent fill 4.12:1 against the bar with 4.58:1 text on it.

Portability

Groups, a tablist and the clients’ own roles; every state renders from the root hooks without a script. The i3 geometry — bar 28px, titles 23px, gaps 14px inner and −2px outer — is reproduced with private variables on this specimen’s root only. Those numbers are reference metrics of the workstation, recorded so a port of the i3 configuration matches it; they are not tokens and not a rule for any other application, which keeps its own window manager, bar and gaps. The specimen proves composition, not a product; only i3 and sway ports draw this frame.

Non-examples

A window with rounded corners or a title bar gradient. A focused window that glows or blurs its neighbours. A shadow under a tiled window; the only shadow is the floating one. Gaps of 14/−2 forced into an unrelated application’s layout. A workspace indicator drawn as a red underline instead of the selection fill. Traffic-light close buttons in the title bar. A translucent bar.

j3w1 / command

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