Accessibility
TermFlow targets terminal apps, where the assistive-technology story is genuinely different from the web: screen readers read the terminal buffer directly, so the practical levers a TUI library has are around colour, motion, and predictable structure.
This page documents the levers TermFlow exposes today.
Colour
Theme.dark,Theme.light, andTheme.monoship as built-in palettes.- Capability detection downgrades cleanly: true-colour → 256 → 16 → 8 →
mono. Apps don't need to branch on the terminal — pick a
Themeand let the renderer downgrade. - The
NO_COLORenvironment variable is honoured: when set, the runtime forcesTheme.mono-equivalent rendering regardless of detected capability.
Reduced motion
Some users find ambient animation actively unhelpful — vestibular
sensitivity, low-bandwidth sessions, screen-reader environments that
re-announce on every frame, or just personal preference. TermFlow
exposes a single flag for this: reducedMotion.
Activating reduced motion
Either set the environment variable:
TERMFLOW_REDUCED_MOTION=1
…or set it in the HOCON config:
termflow {
accessibility {
reduced-motion = true
}
}
The env var takes precedence over the config value when set. Truthy
values are anything other than "0" or "false" (case-insensitive).
What it affects
The flag is plumbed through RuntimeCtx.config.accessibility.reducedMotion
so apps and widgets can read it.
Spinner accepts a reducedMotion: Boolean parameter that, when
true, pins the rendered frame to frames(0) regardless of the tick:
import termflow.tui.widgets.Spinner
def view(model: Model)(using ctx: RuntimeCtx[Msg]): VNode =
Spinner(
Spinner.Braille,
frame = model.tick,
reducedMotion = ctx.config.accessibility.reducedMotion
)
App-level animation (sine wave demos, custom progress effects, anything
driven by Sub.Every purely for cosmetic reasons) should query the
flag and either skip rendering or fall back to a static representation.
What it does not affect
- Functional motion — cursor movement, focus changes, scroll position, dialog open/close. Those are part of the app's behaviour, not cosmetic animation.
- Determinate
ProgressBar— already non-cycling. Only indeterminate progress indicators count as cosmetic motion, and TermFlow'sProgressBaris determinate-only.
Predictable structure
The Elm-style architecture (update is pure, view is a function of
the model) means the rendered frame is fully determined by the model.
That's a foundation accessibility tooling can build on — semantic
annotations, a linear/announcement renderer, or a screen-reader bridge.
Those are post-1.0 work; see the roadmap for current status.