text-reader
Text-to-speech reader with word-level highlighting. Uses the Web Speech API for synthesis and the CSS Custom Highlight API for word tracking.
Overview
The <text-reader> component attaches a text-to-speech control bar to any element. It uses the Web Speech API for synthesis and the CSS Custom Highlight API for real-time word tracking. Progressive enhancement — the component hides itself if the browser lacks speechSynthesis.
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
for | string | — | ID of the element to read. Required. |
selectors | string | p,li | Comma-separated CSS selectors for text extraction within the target |
speed | number | 1 | Initial playback rate (0.5–2) |
voice | string | — | voiceURI to pre-select on load |
highlight | string | — | Set to "false" to disable word highlighting |
scroll | string | — | Set to "false" to disable auto-scroll to active word |
label-play | string | Play | Accessible label for the play button |
label-pause | string | Pause | Accessible label for the pause button |
label-stop | string | Stop | Accessible label for the stop button |
Observed Attributes
These attributes are reactive — changing them at runtime triggers an update:
| Attribute | Behavior on Change |
|---|---|
speed | Restarts speech from the current word at the new rate |
voice | Restarts speech from the current word with the new voice |
for | Stops current speech, re-resolves target element |
JavaScript API
| Method / Property | Type | Description |
|---|---|---|
play() | method | Begin playback (or resume if paused) |
pause() | method | Pause mid-sentence |
resume() | method | Resume from paused state |
stop() | method | Cancel speech and reset position |
voices | Promise<SpeechSynthesisVoice[]> | Available TTS voices |
speaking | boolean | Whether speech is currently active |
paused | boolean | Whether speech is paused |
progress | number (0–1) | Current position as fraction of total text |
Events
| Event | Detail | When |
|---|---|---|
text-reader:play | { voice, speed } | Speech starts |
text-reader:pause | — | Speech paused |
text-reader:resume | — | Speech resumed |
text-reader:stop | — | Stopped or cancelled |
text-reader:end | { duration } | Reached end of text |
text-reader:word | { word, charIndex, element } | Each word boundary |
text-reader:error | { error } | SpeechSynthesis error |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--text-reader-bg | var(--color-surface-raised) | Control bar background |
--text-reader-gap | 0.5rem | Gap between controls |
--text-reader-button-size | 2rem | Button width and height |
--text-reader-highlight | Mark | Word highlight background color |
--text-reader-highlight-text | MarkText | Word highlight text color |
Custom Icons
Replace the default text symbols with custom icons using slot attributes:
Any element with slot="icon-play", slot="icon-pause", or slot="icon-stop" will be moved into the corresponding button.
Accessibility
- Controls are wrapped in a
role="group"witharia-label="Article reader" - Each button has an
aria-label(customizable vialabel-*attributes) - All controls are keyboard-focusable and operable
- Voice select and speed slider have accessible labels
- Highlighting uses system colors (
Mark/MarkText) by default, respecting user contrast preferences - Speech is cancelled on page unload to prevent orphaned audio
Browser Support
| Feature | Chrome | Firefox | Safari | Notes |
|---|---|---|---|---|
| Web Speech API | 33+ | 49+ | 7+ | Core feature |
| CSS Custom Highlight API | 105+ | 117+ | 17.2+ | Word highlighting only |
| Custom Elements | 67+ | 63+ | 10.1+ | Baseline |
adoptedStyleSheets | 73+ | 101+ | 16.4+ | Highlight injection |
Graceful Degradation
| Condition | Behavior |
|---|---|
No speechSynthesis | Element hides itself (display: none) |
No CSS.highlights | Speech works normally, highlighting skipped |
| No target found | Console warning, controls disabled |