Skip to content

Screen-reader accessibility: terminal output has no accessible representation (xterm.js screenReaderMode as reference) #187

Description

@nabramovitz

Context

We are evaluating ghostty-web as a replacement for xterm.js in Cloud Foundry Stratos (SSH and Kubernetes terminals), attracted by the drop-in API aim and by the fact that the canvas renderer injects no <style> elements — which makes it clean under a hardened CSP (style-src-elem with a nonce) where xterm.js is not. Our evaluation notes are recorded here and here.

The API surface covered everything our component uses (Terminal, FitAddon, open, write, onKey, onResize, dispose). The one gap we found is accessibility, and it is the gap that blocks adoption for us, since screen-reader support is on our roadmap.

What exists today

Reading the shipped ghostty-web@0.4.0 dist: the hidden input element is decorated correctly — role="textbox", aria-label="Terminal input", aria-multiline — so focus and typing are visible to a screen reader.

The missing piece

Terminal output has no accessible representation. It is canvas pixels with no parallel text alternative: no aria-live region, no equivalent of xterm's screenReaderMode in the options or published types. A screen-reader user can type into the terminal and hears nothing back.

How xterm.js solves it, as a reference

xterm.js ships this behind an ITerminalOptions.screenReaderMode flag (default off, toggleable at runtime — an option-change listener instantiates or disposes the manager). When enabled, an AccessibilityManager maintains a parallel DOM structure alongside the rendered output:

  • a live region with aria-live="assertive" that announces incoming output as it prints;
  • navigable per-row elements so a user can move through the buffer manually;
  • an overflow guard for floods ("Too much output to announce, navigate to rows manually to read").

The point that makes it relevant here: the mechanism is renderer-independent. The same machinery runs under xterm's WebGL renderer — that is VS Code's "screen reader optimized" terminal — so a canvas-rendered terminal and screen-reader access are not in tension. The announcement layer just has to exist alongside the canvas.

Since ghostty-web aims to be API-compatible with xterm.js, screenReaderMode seems like the natural shape for it here too: opt-in, no cost when disabled, and migrations with accessibility requirements can carry their existing option through unchanged.

Happy to share more detail from our evaluation if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions