Diagnostics
Inline problem markers in code (underline patterns, an error line and an overview stripe) and the problems panel that lists them as a listbox, each severity carrying its glyph.
stable · light DOM · 4.0.0. Light DOM retains static content, native semantics, label relationships and host composition without duplicating controls.
Live variants
inline
✕ Language server stopped; markers may be stale.
import { readFile } from "node:fs/promises"; const title = document.title; function render(frame) { const count = frame.children.length; escape(title); return frmae.title + count; } render(document.body) == null;
No problems in title.js
<j3w1-diagnostics id="example-diagnostics-inline"><div class="diagnostics diagnostics-inline">
<p class="diagnostics-status" role="status">✕ Language server stopped; markers may be stale.</p>
<div class="diagnostics-box" role="textbox" aria-multiline="true" aria-readonly="true" aria-label="title.js with 6 diagnostics, read-only" tabindex="0">
<pre class="diagnostics-code"><span class="diagnostics-line"><span class="diagnostics-ln" aria-hidden="true">1</span><span class="diagnostics-text">import { <span class="diagnostics-unused" title="readFile is declared but never used">readFile</span> } from "node:fs/promises";</span><span class="diagnostics-mark diagnostics-mark-hint" aria-hidden="true">·</span></span>
<span class="diagnostics-line"><span class="diagnostics-ln" aria-hidden="true">2</span><span class="diagnostics-text">const title = document.title;</span><span class="diagnostics-mark" aria-hidden="true"></span></span>
<span class="diagnostics-line"><span class="diagnostics-ln" aria-hidden="true">3</span><span class="diagnostics-text">function <span class="diagnostics-hint" title="Hint: render could be an arrow function">render</span>(frame) {</span><span class="diagnostics-mark diagnostics-mark-hint" aria-hidden="true">·</span></span>
<span class="diagnostics-line"><span class="diagnostics-ln" aria-hidden="true">4</span><span class="diagnostics-text"> const count = <span class="diagnostics-info" title="Info: frame.children may be undefined; consider ?.">frame.children</span>.length;</span><span class="diagnostics-mark diagnostics-mark-info" aria-hidden="true">i</span></span>
<span class="diagnostics-line"><span class="diagnostics-ln" aria-hidden="true">5</span><span class="diagnostics-text"> <span class="diagnostics-deprecated" title="escape() is deprecated">escape</span>(title);</span><span class="diagnostics-mark diagnostics-mark-hint" aria-hidden="true">·</span></span>
<span class="diagnostics-line diagnostics-line-error"><span class="diagnostics-ln" aria-hidden="true">6</span><span class="diagnostics-text"> return <span class="diagnostics-error" title="Error: frmae is not defined">frmae</span>.title + count;</span><span class="diagnostics-mark diagnostics-mark-error" aria-hidden="true">✕</span></span>
<span class="diagnostics-line"><span class="diagnostics-ln" aria-hidden="true">7</span><span class="diagnostics-text">}</span><span class="diagnostics-mark" aria-hidden="true"></span></span>
<span class="diagnostics-line"><span class="diagnostics-ln" aria-hidden="true">8</span><span class="diagnostics-text">render(document.body) <span class="diagnostics-warning diagnostics-target" title="Warning: expected === and instead saw ==">==</span> null;</span><span class="diagnostics-mark diagnostics-mark-warning" aria-hidden="true">!</span></span></pre>
</div>
<p class="diagnostics-empty"><span class="diagnostics-glyph diagnostics-glyph-success" aria-hidden="true">✓</span> No problems in title.js</p>
</div></j3w1-diagnostics>panel
✕ Language server stopped; the list may be stale.
- title.js:6:10 no-undef
- title.js:8:23 eqeqeq
- title.js:4:17 ts-2532
- title.js:1:10 no-unused-vars
- title.js:5:3 deprecation
No problems
<j3w1-diagnostics id="example-diagnostics-panel"><div class="diagnostics diagnostics-panel">
<div class="diagnostics-header">
<span class="diagnostics-title" id="example-diagnostics-panel-dg-title">Problems</span>
<span class="diagnostics-count"><span class="diagnostics-glyph diagnostics-glyph-error">✕</span> 1 <span class="sr-only">error</span></span>
<span class="diagnostics-count"><span class="diagnostics-glyph diagnostics-glyph-warning">!</span> 1 <span class="sr-only">warning</span></span>
<span class="diagnostics-count"><span class="diagnostics-glyph diagnostics-glyph-info">i</span> 1 <span class="sr-only">info</span></span>
<span class="diagnostics-count"><span class="diagnostics-glyph diagnostics-glyph-hint">·</span> 3 <span class="sr-only">hints</span></span>
</div>
<p class="diagnostics-status" role="status">✕ Language server stopped; the list may be stale.</p>
<ul class="diagnostics-list" role="listbox" aria-labelledby="example-diagnostics-panel-dg-title" aria-activedescendant="example-diagnostics-panel-dg-row-2" tabindex="0">
<li class="diagnostics-row" role="option" id="example-diagnostics-panel-dg-row-1" aria-selected="false">
<span class="diagnostics-glyph diagnostics-glyph-error" aria-hidden="true">✕</span>
<span class="diagnostics-message"><span class="sr-only">Error: </span>frmae is not defined</span>
<span class="diagnostics-loc">title.js:6:10</span>
<span class="diagnostics-rule">no-undef</span>
</li>
<li class="diagnostics-row diagnostics-row-active" role="option" id="example-diagnostics-panel-dg-row-2" aria-selected="false">
<span class="diagnostics-glyph diagnostics-glyph-warning" aria-hidden="true">!</span>
<span class="diagnostics-message"><span class="sr-only">Warning: </span>Expected === and instead saw ==</span>
<span class="diagnostics-loc">title.js:8:23</span>
<span class="diagnostics-rule">eqeqeq</span>
</li>
<li class="diagnostics-row" role="option" id="example-diagnostics-panel-dg-row-3" aria-selected="false">
<span class="diagnostics-glyph diagnostics-glyph-info" aria-hidden="true">i</span>
<span class="diagnostics-message"><span class="sr-only">Info: </span>frame.children may be undefined; consider optional chaining</span>
<span class="diagnostics-loc">title.js:4:17</span>
<span class="diagnostics-rule">ts-2532</span>
</li>
<li class="diagnostics-row" role="option" id="example-diagnostics-panel-dg-row-4" aria-selected="false">
<span class="diagnostics-glyph diagnostics-glyph-hint" aria-hidden="true">·</span>
<span class="diagnostics-message"><span class="sr-only">Hint: </span>readFile is declared but never used</span>
<span class="diagnostics-loc">title.js:1:10</span>
<span class="diagnostics-rule">no-unused-vars</span>
</li>
<li class="diagnostics-row" role="option" id="example-diagnostics-panel-dg-row-5" aria-selected="false">
<span class="diagnostics-glyph diagnostics-glyph-hint" aria-hidden="true">·</span>
<span class="diagnostics-message"><span class="sr-only">Hint: </span>escape() is deprecated; use encodeURIComponent()</span>
<span class="diagnostics-loc">title.js:5:3</span>
<span class="diagnostics-rule">deprecation</span>
</li>
</ul>
<p class="diagnostics-empty"><span class="diagnostics-glyph diagnostics-glyph-success" aria-hidden="true">✓</span> No problems</p>
</div></j3w1-diagnostics>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.0import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/diagnostics.css';
import '@j3w1/ui/register/diagnostics';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.
Copy the complete implementation
npx --package=@j3w1/ui@4.0.0 j3w1-ui copy diagnostics --out ./vendor/j3w1/diagnosticsThe 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
| Name | Type / signature | Meaning |
|---|---|---|
disabled | CustomEvent | Disable the native controls owned by this instance. |
loading | CustomEvent | Mark the primary control busy and prevent duplicate activation. |
properties
| Name | Type / signature | Meaning |
|---|---|---|
disabled | boolean | Delegates disabled state to native children. |
name | string | Native control name; application form keys remain explicit. |
methods
| Name | Type / signature | Meaning |
|---|---|---|
refresh | (): void | Reconnect behavior after replacing native child structure. |
focus | (options?: FocusOptions): void | Focus the first usable native control. |
setText | (text: string): void | Replace the bounded read-only text view; no code or shell execution occurs. |
events
| Name | Type / signature | Meaning |
|---|---|---|
j3w1-action | CustomEvent | Request a developer-view action; editing and execution belong to the host. |
Dependencies and verification
Registered components: none. Style dependencies: none.
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
Diagnostics diagnostics
Inline problem markers in code (underline patterns, an error line and an overview stripe) and the problems panel that lists them as a listbox, each severity carrying its glyph.
Report an issue with this component
Tokens
Focus a role to inspect its values; follow its link for persistent usage and source details.
| Part | Role | Value | Use |
|---|---|---|---|
root.bg | color.surface.defaultapproveduse | #0d0707 | D-041 surface.default: color.primitive.modern.panel. |
root.border | color.border.controlapproveduse | #c81a1a | D-041 owner correction: red control and floating-frame borders, distinct from rose text. |
code.bg | color.code.bgapproveduse | #000000 | D-041 code.bg: color.primitive.ink.0. |
code.text | color.text.defaultapproveduse | #e99499 | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
code.line-number | color.code.line-numberapproveduse | #bd787d | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
code.gutter-rule | color.code.gutter-ruleapproveduse | #482b2b | D-041 code.gutter-rule: color.primitive.modern.divider. |
code.selection-bg | color.code.selection-bgobserveduse | #420f0c | Editor selection background (muted text stays 4.71:1). |
error.underline | color.diagnostic.error.underlineobserveduse | #e53935 | Error wavy underline. |
error.text | color.diagnostic.error.textobserveduse | #f73f35 | Error message text. |
error.stripe | color.diagnostic.error.stripeobserveduse | #e53935 | Error stripe mark. |
error.line-bg | color.diagnostic.error.bgobserveduse | #2b0e0d | Error line background. |
warning.underline | color.diagnostic.warning.underlineapproveduse | #e5c07b | D-041 diagnostic.warning.underline: color.primitive.modern.amber. |
warning.text | color.diagnostic.warning.textapproveduse | #e5c07b | D-041 diagnostic.warning.text: color.primitive.modern.amber. |
warning.stripe | color.diagnostic.warning.stripeapproveduse | #e5c07b | D-041 diagnostic.warning.stripe: color.primitive.modern.amber. |
info.underline | color.diagnostic.info.underlineapproveduse | #82b4ff | D-041 diagnostic.info.underline: color.primitive.modern.blue. |
info.text | color.diagnostic.info.textapproveduse | #82b4ff | D-041 diagnostic.info.text: color.primitive.modern.blue. |
hint.underline | color.diagnostic.hint.underlineapproveduse | #bd787d | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
hint.text | color.text.subtleapproveduse | #bd787d | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
unused.text | color.diagnostic.unused.textapproveduse | #d4868b | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
deprecated.text | color.code.syntax.deprecatedapproveduse | #bd787d | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
row.text | color.text.defaultapproveduse | #e99499 | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
row.location | color.text.mutedapproveduse | #d4868b | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
row.divider | color.border.dividerapproveduse | #482b2b | D-041 border.divider: color.primitive.modern.divider. |
row.bg-hover | color.interaction.hover.bgapproveduse | #1c1010 | D-041 interaction.hover.bg: color.primitive.modern.hover. |
row.ring | color.interaction.focus.ringobserveduse | #e53935 | 1px dashed focus ring on controls and rows. |
row.bg-selected | color.interaction.selection.bgapproveduse | #531310 | Selected row, tab, workspace; D-027 recessed the fill, leaving the 2px indicator and the check to carry selection. |
row.text-selected | color.interaction.selection.textobserveduse | #f4eeee | Text on the selection. |
row.ring-selected | color.interaction.focus.ringobserveduse | #e53935 | 1px dashed focus ring on controls and rows. |
header.text | color.text.brightapproveduse | #ffa2a7 | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
status.text | color.status.danger.textobserveduse | #f07178 | D-041 readable error text on neutral surfaces and native warning tints. |
empty.text | color.text.mutedapproveduse | #d4868b | D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills. |
empty.glyph | color.status.success.textapproveduse | #82d9a0 | D-041 status.success.text: color.primitive.modern.green. |
State matrix
Every declared state and combination, statically rendered; the default cell is live. Sizes: compact, comfortable (switch with the density control above).
| State | Inline markers | Problems panel |
|---|---|---|
default | ✕ Language server stopped; markers may be stale. import { readFile } from "node:fs/promises"; const title = document.title; function render(frame) { const count = frame.children.length; escape(title); return frmae.title + count; } render(document.body) == null; No problems in title.js |
Problems
✕ 1 error
! 1 warning
i 1 info
· 3 hints
✕ Language server stopped; the list may be stale.
No problems |
hover | ||
focus-visible | ||
selected | ||
selected+focus-visible | ||
error | ||
empty |
Purpose
How problems appear on code and in the list that indexes them. Six kinds, each told apart by pattern and glyph as well as colour. The panel is the keyboard route to every marker.
Anatomy
Root .diagnostics with .diagnostics-inline or .diagnostics-panel.
Inline: .diagnostics-code (the <pre>), -line, -ln, -text, -mark
(the stripe cell) and the ranges .diagnostics-error, -warning, -info,
-hint, -unused, -deprecated; .diagnostics-line-error is the filled
row; .diagnostics-target is the range of the selected row. Panel:
-header, -title, -count, -status, -list, -row, -glyph (with
-glyph-error and so on), -message, -loc, -rule, -empty.
Patterns: error and warning wavy, info and hint dotted, unused dotted in
color.diagnostic.unused.text, deprecated line-through in
color.code.syntax.deprecated. Glyphs: ✕ error in
color.diagnostic.error.text, ! warning in color.diagnostic.warning.text,
i info in color.diagnostic.info.text, · hint in color.text.subtle.
The stripe mark repeats the glyph in the stripe colour
(color.diagnostic.error.stripe, color.diagnostic.warning.stripe).
States
| State | Visual | Non-colour channel |
|---|---|---|
| default | ranges decorated on color.code.bg; the error row filled color.diagnostic.error.bg; panel rows on color.surface.default, 1px color.border.divider between | underline pattern; glyph |
| hover | panel row → color.interaction.hover.bg; inline ranges unchanged (the hover tooltip is a host surface) | cursor: default on rows |
| focus-visible | active row: 1px dashed color.interaction.focus.ring at −2px; inline box: 2px color.interaction.focus.ring-container at −3px | the ring |
| selected | row filled color.interaction.selection.bg, text and glyph color.interaction.selection.text; the matching inline range filled color.code.selection-bg under its underline | aria-selected; the glyph stays; the fill spans the row |
| selected+focus-visible | the selection fill and 1px dashed color.interaction.focus.ring at −2px | both at once |
| error | provider failed: a role=status line with ✕ in color.status.danger.text above the stale rows; the stripe shows the same ✕ at its top | glyph; live announcement |
| empty | rows, stripe marks and inline decorations removed; ✓ No problems in color.text.muted, glyph in color.status.success.text | glyph; the absence of decoration |
Precedence: selected > hover; focus-visible is drawn on top. A selected row recolours its glyph to the on-selection text, so the shape, not the hue, carries the severity.
Keyboard
As in the key table; next and previous problem and the hover card belong to the host.
Accessibility
Never colour-only: the underline pattern in code, the glyph in the panel, and
the glyph is part of the option’s accessible name (“Error: frmae is not
defined, title.js line 6”). The error row fill adds to the wavy underline,
never replaces it. Text, including unused code, meets 4.5:1; every underline
meets 3:1 on its actual background, the selected range included. The status
line is announced once. In forced-colours mode the patterns persist because
they are text-decoration, not backgrounds.
Portability
Where wavy is unavailable the port uses a plain underline plus the glyph and records the deviation. Hosts with their own overview ruler map the stripe colours; hosts without one omit the stripe and keep the glyphs.
Non-examples
Red-only errors without ✕ or the wavy pattern. Wavy for every severity.
Purple or cyan for info and hint. A row hover that changes only text colour.
A selected row whose glyph keeps its severity colour on the fill. A rounded
highlight or left accent bar instead of the row fill. Removing the error line
fill to “calm” the editor.
Contrast report
32 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.
| Pair | State | Kind | Foreground | Background | Ratio | Min | Result |
|---|---|---|---|---|---|---|---|
| diagnostics default text | default | text | color.text.default #e99499 | color.surface.default #0d0707 | 8.72 | 4.5 | pass |
| diagnostics default border | default | ui | color.border.control #c81a1a | color.surface.default #0d0707 | 3.44 | 3 | pass |
| diagnostics hover text | hover | text | color.text.default #e99499 | color.interaction.hover.bg #1c1010 | 8.10 | 4.5 | pass |
| diagnostics focus-visible text | focus-visible | text | color.text.default #e99499 | color.surface.default #0d0707 | 8.72 | 4.5 | pass |
| diagnostics focus-visible outline | focus-visible | ui | color.interaction.focus.ring #e53935 | color.surface.default #0d0707 | 4.73 | 3 | pass |
| diagnostics selected text | selected | text | color.interaction.selection.text #f4eeee | color.interaction.selection.bg #531310 | 12.47 | 4.5 | pass |
| diagnostics selected+focus-visible text | selected+focus-visible | text | color.interaction.selection.text #f4eeee | color.interaction.selection.bg #531310 | 12.47 | 4.5 | pass |
| diagnostics selected+focus-visible outline | selected+focus-visible | ui | color.interaction.focus.ring #e53935 | color.interaction.selection.bg #531310 | 3.38 | 3 | pass |
| diagnostics error text | error | text | color.status.danger.text #f07178 | color.surface.default #0d0707 | 6.98 | 4.5 | pass |
| diagnostics empty text | empty | text | color.text.muted #d4868b | color.surface.default #0d0707 | 7.22 | 4.5 | pass |
| code text | — | text | color.text.default #e99499 | color.code.bg #000000 | 9.16 | 4.5 | pass |
| code text on the error line | — | text | color.text.default #e99499 | color.diagnostic.error.bg #2b0e0d | 7.82 | 4.5 | pass |
| error glyph on the error line | — | text | color.diagnostic.error.text #f73f35 | color.diagnostic.error.bg #2b0e0d | 4.88 | 4.5 | pass |
| error underline | — | ui | color.diagnostic.error.underline #e53935 | color.code.bg #000000 | 4.97 | 3 | pass |
| error underline on the error line | — | ui | color.diagnostic.error.underline #e53935 | color.diagnostic.error.bg #2b0e0d | 4.24 | 3 | pass |
| warning underline inside the selected range | selected | ui | color.diagnostic.warning.underline #e5c07b | color.code.selection-bg #420f0c | 9.31 | 3 | pass |
| warning underline | — | ui | color.diagnostic.warning.underline #e5c07b | color.code.bg #000000 | 12.16 | 3 | pass |
| info underline | — | ui | color.diagnostic.info.underline #82b4ff | color.code.bg #000000 | 9.92 | 3 | pass |
| hint underline | — | ui | color.diagnostic.hint.underline #bd787d | color.code.bg #000000 | 6.15 | 3 | pass |
| unused text | — | text | color.diagnostic.unused.text #d4868b | color.code.bg #000000 | 7.58 | 4.5 | pass |
| deprecated text | — | text | color.code.syntax.deprecated #bd787d | color.code.bg #000000 | 6.15 | 4.5 | pass |
| error stripe mark | — | ui | color.diagnostic.error.stripe #e53935 | color.code.bg #000000 | 4.97 | 3 | pass |
| warning stripe mark | — | ui | color.diagnostic.warning.stripe #e5c07b | color.code.bg #000000 | 12.16 | 3 | pass |
| info stripe mark | — | ui | color.diagnostic.info.text #82b4ff | color.code.bg #000000 | 9.92 | 3 | pass |
| error glyph and count in the panel | — | text | color.diagnostic.error.text #f73f35 | color.surface.default #0d0707 | 5.44 | 4.5 | pass |
| warning glyph and count in the panel | — | text | color.diagnostic.warning.text #e5c07b | color.surface.default #0d0707 | 11.57 | 4.5 | pass |
| info glyph and count in the panel | — | text | color.diagnostic.info.text #82b4ff | color.surface.default #0d0707 | 9.44 | 4.5 | pass |
| hint glyph in the panel | — | text | color.text.subtle #bd787d | color.surface.default #0d0707 | 5.85 | 4.5 | pass |
| location and rule code | — | text | color.text.muted #d4868b | color.surface.default #0d0707 | 7.22 | 4.5 | pass |
| row text on hover | hover | text | color.text.default #e99499 | color.interaction.hover.bg #1c1010 | 8.10 | 4.5 | pass |
| error glyph on hover | hover | text | color.diagnostic.error.text #f73f35 | color.interaction.hover.bg #1c1010 | 5.06 | 4.5 | pass |
| the ✓ of the empty message | empty | text | color.status.success.text #82d9a0 | color.surface.default #0d0707 | 11.79 | 4.5 | pass |
Keys
| Key | Action |
|---|---|
| Tab / Shift+Tab | Moves focus to and from the list as one stop; the active row is restored. |
| Down / Up | Moves the active row; selection follows focus in this single-select listbox. |
| Home / End | First or last row. |
| Enter | Opens the location in the editor and moves focus there. |
| Type-ahead | Jumps to the next row whose message starts with the typed characters. |
| (host) | Inline markers have no keyboard of their own; navigation between problems (F8-style) is the host's binding. |
For agents
Component JSON ·Implementation brief ·Build a task kit ·
Related: code-editor diff-view terminal
Stress fixtures: FX-STATE-MATRIX FX-320 FX-ZOOM-200 FX-RM FX-HC FX-LONG FX-I18N