Here is a vanilla JS/HTML version:
let count = 1
let timer = null
let controller = new AbortController()
const synth = window.speechSynthesis
const utter = new SpeechSynthesisUtterance(count)
const text = document.getElementById('text')
const onUtterEnd = () => {
count = count + 1
utter.text = count
text.innerHTML = `<mark>${count}</mark>`
synth.speak(utter)
}
const start = () => {
text.innerHTML = `<mark>${count}</mark>`
controller = new AbortController()
utter.addEventListener('end', onUtterEnd, { signal: controller.signal })
synth.speak(utter)
}
const stop = () => {
controller.abort()
synth.cancel()
}
document.getElementById('start').addEventListener('click', start)
document.getElementById('stop').addEventListener('click', stop)
<button id="start">start</button>
<button id="stop">stop</button>
<p id="text"></p>
If you're using React you can use tts-react
. Here is an example (change the counter
logic to match your preferred way of counting):
import { useTts } from 'tts-react'
import { useState, useEffect } from 'react'
const SpeakCountedNumbers = () => {
const [count, setCount] = useState(1)
const { ttsChildren, play } = useTts({
children: count,
rate: 0.9,
markTextAsSpoken: true,
onEnd: useCallback(() => {
setCount((prev) => prev + 1)
}, [])
})
useEffect(() => {
play()
}, [count, play])
return <>{ttsChildren}</>
}
This will render the number sequence, 1, 2, 3, ... while speaking each number and highlighting it in the document.
See it on Codesandbox. Certain browsers may require you to click the document (or interact with it in some way) before audio starts playing, for example Chrome.