DEV Community

Cover image for Text to Speech Converter in HTML, CSS, and Javascript
Ashutosh Tiwari
Ashutosh Tiwari

Posted on • Originally published at incoderweb.blogspot.com

Text to Speech Converter in HTML, CSS, and Javascript

Hello friends, today in this blog, we will learn how to create a text-to-speech converter in HTML, CSS, and Javascript. In our previous blog, we saw how to create a responsive personal portfolio design using HTML, CSS, and Javascript. Earlier I shared many projects related to HTML, CSS, and Javascript. You can check here. Now it's time to create a text-to-speech converter. If you are interested then you can check my other javascript projects after reading this blog. My Javascript blogs.

Text to Speech (TTS) converter is a type of assistive technology that reads text aloud. It is also called "Read Aloud". With a click of a button and or the touch of a finger, TTS can take words from computers or other devices and convert them into audio.

You may like these:-

It works with nearly every personal digital device, including computers, smartphones, and tablets. All kinds of text files can be read aloud, including Word and Pages documents. Even online web pages can be read aloud.

In this design [Text to Speech Converter], there is a converter with a beautiful design as you can see in the image above, there is a textarea to enter text, and there are options for speed and pitch of speech. You can select the voice of speech as well and then click on the convert button the speech will start. If you are unable to understand me then you can check the source code and preview it as well.

Preview of this text to speech converter is available here.

HTML Code

<!-- --------------------- Created By InCoder --------------------- -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Text to Speach - InCoder</title>
    <link rel="stylesheet" href="main.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
</head>
<body>
    <div class="container">
        <div class="title">Text to Speech Converter</div>
        <div class="text">
            <textarea placeholder="Enter Text" id="text" cols="30" rows="5"></textarea>
        </div>
        <div class="rate">
            <span>1</span>
            <p>Speed</p>
            <input type="range" min="0" max="3" id="rate" value="1">
        </div>
        <div class="pitch">
            <span>1</span>
            <p>Voice Pitch</p>
            <input type="range" min="0" max="10" id="pitch" value="1">
        </div>
        <select id="voices">
        </select>
        <button class="convert">Convert</button>
    </div>

    <script src="script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

CSS Code

/* --------------------- Created By InCoder --------------------- */

@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap");

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Poppins", sans-serif;
}

body {
  display: flex;
  height: 100vh;
  background: #000;
  align-items: center;
  justify-content: center;
}

.container {
  margin: 0 1rem;
  padding: 0 1.2rem;
  text-align: center;
  border-radius: 0.4rem;
  width: clamp(20rem, 4vw, 30rem);
  background: rgb(255 255 255 / 80%);
}

.container .title {
  font-weight: 600;
  font-size: 1.4rem;
  margin-top: 0.4rem;
  margin-bottom: 0.4rem;
}

.container .text textarea {
  width: 100%;
  padding: 0.4rem;
  border-radius: 0.6rem;
  border: 2px solid rgb(0 0 0 / 20%);
  background: rgb(255 255 255 / 70%);
}

.container .text textarea:focus {
  outline: none;
  border: 2px solid rgb(39 181 197);
}

.container :is(.rate, .pitch) {
  position: relative;
  margin-top: 1rem;
}

.container :is(.rate, .pitch) span {
    top: 0;
    right: 0;
    width: 1.3rem;
    height: 1.5rem;
    position: absolute;
    border-radius: 0.1rem;
    background: rgb(255 255 255 / 50%);
}

.container :is(.rate, .pitch) p {
    font-size: .8rem;
    width: fit-content;
}

.container :is(.rate, .pitch) input[type="range"] {
  width: 100%;
  background-color: rgb(39 181 197);
}

.container :is(.rate, .pitch) input[type="range"] {
  width: 100%;
  opacity: 0.7;
  outline: none;
  height: 0.2rem;
  -webkit-appearance: none;
  -webkit-transition: 0.2s;
  transition: opacity 0.2s;
  background: rgb(0 0 0 / 30%);
}

.container :is(.rate, .pitch) input[type="range"]:hover {
  opacity: 1;
}

.container :is(.rate, .pitch) input[type="range"]::-webkit-slider-thumb {
  width: 1rem;
  height: 1rem;
  cursor: grab;
  appearance: none;
  border-radius: 50%;
  -webkit-appearance: none;
  background: rgb(39 181 197);
}

.container :is(.rate, .pitch) input[type="range"]::-moz-range-thumb {
  width: 1rem;
  height: 1rem;
  cursor: grab;
  background: rgb(39 181 197);
}

.container .convert {
  width: 100%;
  cursor: pointer;
  padding: 0.2rem 0;
  margin-top: .6rem;
  font-size: 1.1rem;
  margin-bottom: 1rem;
  border-radius: 0.6rem;
  color: rgb(0 0 0 / 80%);
  border: 1px solid transparent;
  background: rgb(255 255 255 / 50%);
}

.container button:focus {
  outline: 2px solid rgb(0 0 0 / 40%);
}

#voices {
  border: 0;
  width: 100%;
  height: 2.4rem;
  margin-top: 0.6rem;
  border-radius: 0.4rem;
  padding: 0 0 0 0.5rem;
  background: rgb(255 255 255 / 50%)
    url("data:image/svg+xml,<svg height='10px' width='10px' viewBox='0 0 16 16' fill='%23000000' xmlns='http://www.w3.org/2000/svg'><path d='M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z'/></svg>")
    no-repeat;
  background-position: calc(100% - 0.75rem) center !important;
  -moz-appearance: none !important;
  -webkit-appearance: none !important;
  appearance: none !important;
  padding-right: 2rem !important;
}

#voices:focus {
    outline: 2px solid rgb(0 0 0 / 40%);
}

#voices option {
    padding: 2rem;
}
Enter fullscreen mode Exit fullscreen mode

Javascript Code

// --------------------- Created By InCoder ---------------------

let text = document.querySelector('#text')
rate = document.querySelector('#rate')
pitch = document.querySelector('#pitch')
play = document.querySelector('#play')
stopSpeech = document.querySelector('#stop')
convert = document.querySelector('.convert')
voicesOptions = document.querySelector('#voices')

let voices = []

let synth = speechSynthesis

const getVoices = () => {
    voices = synth.getVoices()

    voices.forEach(voice => {
        let option = document.createElement('option')
        option.innerText = `${voice.name}`
        option.setAttribute('value', voice.name)
        option.setAttribute('data-name', voice.name)
        option.setAttribute('data-lang', voice.lang)
        voicesOptions.appendChild(option)
    })
}

getVoices()

if (synth.onvoiceschanged !== undefined) {
    synth.onvoiceschanged = getVoices
}

const convertToSpeach = () => {
    if (synth.speaking) {
        return
    }

    if (text.value !== '') {
        let speakText = new SpeechSynthesisUtterance(text.value)

        speakText.onend = e => {
            convert.disabled = false
        }

        speakText.onerror = e => {
            console.log('Something Went Wrong....')
        }

        let selectedVoice = voicesOptions.value

        voices.forEach(voice => {
            if (voice.name == selectedVoice) {
                speakText.voice = voice
            }
        })
        speakText.rate = rate.value
        speakText.pitch = pitch.value
        convert.disabled = true

        synth.speak(speakText)
    }

    voicesOptions.addEventListener('change', () => {
        synth.cancel()
        convertToSpeach()
    })

    rate.addEventListener('change', () => {
        synth.cancel()
        convertToSpeach()
        document.querySelector('.rate span').innerText = rate.value
    })

    pitch.addEventListener('change', () => {
        synth.cancel()
        convertToSpeach()
        document.querySelector('.pitch span').innerText = pitch.value
    })

}

rate.addEventListener('change', () => {
    document.querySelector('.rate span').innerText = rate.value
})

pitch.addEventListener('change', () => {
    document.querySelector('.pitch span').innerText = pitch.value
})


convert.addEventListener('click', convertToSpeach)
Enter fullscreen mode Exit fullscreen mode

Discussion (0)