Environment
@solidtv/solid 1.2.2
- Platform: LG webOS TV, Audio Guidance (the OS screen reader) enabled
- App is a WebGL
<canvas> Lightning app (no DOM UI), using Announcer with aria = true
Summary
In ARIA mode (Announcer.aria = true), Announcer.speak correctly injects the label into the #aria-parent aria-live="assertive" region — but then deletes those nodes 100 ms later and moves focus back to the canvas.
On the TV screen reader, that teardown fires before the reader has finished (often before it has started)
speaking the label, so nothing is announced, even though the DOM mutates exactly as
expected.
The hard-coded 100 ms is too aggressive for TV readers.
Where
src/primitives/announcer/speech.ts, in focusElementForAria():
// Cleanup
setTimeout(() => {
ariaLabelPhrases = [];
cleanAriaLabelParent(); // removes the spans that were just injected
focusCanvas(); // moves focus back to the canvas
}, 100);
(The cancel() path in speakSeries does the same immediate clear + focusCanvas().)
Steps to reproduce
On a webOS TV with Audio Guidance on, drive Announcer.speak(['Hello', 'button']) in
aria mode on focus change. Observe: the spans appear in #aria-parent and disappear ~100
ms later; nothing is spoken.
Proposed fix
Don't tear the content down on a timer. Either of:
- Replace-on-next-write (preferred): leave the injected label in the region until the
next announcement replaces it. The region naturally holds only the current label, and
the reader is never interrupted.
- Make the teardown configurable: expose the cleanup delay (and whether to
focusCanvas()), e.g. Announcer.ariaCleanupDelay, defaulting to something safe
(≥ a few seconds) or 0/off.
Environment
@solidtv/solid1.2.2<canvas>Lightning app (no DOM UI), usingAnnouncerwitharia = trueSummary
In ARIA mode (
Announcer.aria = true),Announcer.speakcorrectly injects the label into the#aria-parentaria-live="assertive"region — but then deletes those nodes 100 ms later and moves focus back to the canvas.On the TV screen reader, that teardown fires before the reader has finished (often before it has started)
speaking the label, so nothing is announced, even though the DOM mutates exactly as
expected.
The hard-coded 100 ms is too aggressive for TV readers.
Where
src/primitives/announcer/speech.ts, infocusElementForAria():(The
cancel()path inspeakSeriesdoes the same immediate clear +focusCanvas().)Steps to reproduce
On a webOS TV with Audio Guidance on, drive
Announcer.speak(['Hello', 'button'])inaria mode on focus change. Observe: the spans appear in
#aria-parentand disappear ~100ms later; nothing is spoken.
Proposed fix
Don't tear the content down on a timer. Either of:
next announcement replaces it. The region naturally holds only the current label, and
the reader is never interrupted.
focusCanvas()), e.g.Announcer.ariaCleanupDelay, defaulting to something safe(≥ a few seconds) or
0/off.