Create an Online Text-to-Speech Converter Tool in Blogger with HTML, CSS, and JavaScript

Creating a Text-to-Speech (TTS) converter can be an excellent project to add interactivity and functionality to your Blogger website. With modern web technologies like HTML, CSS, and JavaScript, building a TTS tool is both simple and effective. This blog will guide you through the process, providing source code and step-by-step instructions.

Table of Contents

  1. What is a Text-to-Speech Converter?
  2. Step-by-Step Implementation
    • Embedding Code in Blogger
    • HTML for Structure
    • CSS for Styling
    • JavaScript for Functionality
  3. Testing the Tool
  4. Customizing the Tool
  5. Conclusion

1. What is a Text-to-Speech Converter?

A Text-to-Speech converter transforms written text into spoken audio using synthesized voices. It's widely used for accessibility, content consumption on the go, and learning applications. You can check the preview of this tool on TONTUF Tools

2. Step-by-Step Implementation

Follow these steps to embed your Text-to-Speech converter tool in Blogger:

a. Embedding Code in Blogger

  1. Log in to your Blogger account.
  2. Go to the Theme section and click Customize > Edit HTML.
  3. Identify the section where you want the TTS tool (e.g., sidebar or blog post content area).
  4. Copy and paste the following HTML, CSS, and JavaScript code into the appropriate location.

b. HTML for Structure

This code defines the structure of the TTS tool.

<div class="tts-container">
  <h2>Text-to-Speech Converter</h2>
  <textarea id="text-input" placeholder="Type or paste text here"></textarea>
  <button id="speak-btn">Speak</button>
</div>

c. CSS for Styling

Add the following CSS code for styling:

<style>
.tts-container {
  font-family: Arial, sans-serif;
  max-width: 400px;
  margin: 20px auto;
  text-align: center;
  padding: 15px;
  border: 1px solid #ccc;
  border-radius: 8px;
  background-color: #f9f9f9;
}

#text-input {
  width: 100%;
  height: 100px;
  margin-bottom: 10px;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

#speak-btn {
  padding: 10px 20px;
  background-color: #007bff;
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

#speak-btn:hover {
  background-color: #0056b3;
}
</style>

d. JavaScript for Functionality

The following JavaScript code utilizes the Web Speech API to convert text to speech.

<script>
document.getElementById('speak-btn').addEventListener('click', function() {
  const text = document.getElementById('text-input').value;
  if (text.trim() !== '') {
    const speech = new SpeechSynthesisUtterance(text);
    window.speechSynthesis.speak(speech);
  } else {
    alert('Please enter some text!');
  }
});
</script>

5. Testing the Tool

  1. Save your changes and refresh your Blogger site.
  2. Navigate to the section where you added the TTS tool.
  3. Test it by typing text into the input box and clicking the Speak button. Ensure that your browser supports the Web Speech API.

6. Customizing the Tool

Here are some ideas to personalize the TTS tool:

  • Add Voice Options: Enable users to select from different voices or languages.
  • Adjust Speed and Pitch: Provide sliders to control speech speed and pitch.
  • Save Settings: Use localStorage to remember user preferences.
  • Mobile Responsiveness: Optimize the design for mobile devices.
You can use the below code if you want this tool with more customizations

<style>


.main {
  margin: auto;
  width: 100%;
}

.padding {
  padding: 12px;
}

.padding-semi-large {
  padding: 14px 0px;
}

h2 {
  font-size: 34px;
  font-weight: var(--header-font-weight);
  text-align: left;
  line-height: 125%;
  margin: auto;
}

p {
  font-size: 18px;
  line-height: 160%;
  margin: auto;
  font-weight: var(--body-font-weight);
}

#indicators {
  display: flex;
  flex-direction: row;
  padding-top: 20px;
  align-items: center;
}

#repo-links {
  display: flex;
  flex-direction: row;
  align-items: center;
}

.indicator-separator {
  padding-left: 7px;
  padding-right: 7px;
}

.indicator {
  font-size: 16px;
  color: #00000059;
  font-weight: 400;
}

#indicators a {
  text-underline-offset: 1px;
  transition: 0.2s;
}

#indicators a:hover {
  color: var(--small-link-color);
}

.icon-link {
  width: 16px;
  padding-left: 7px;
}

.icon-link-small {
  width: 14px;
  padding-left: 7px;
}

.link {
  color: var(--link-color);
  text-decoration: none;
  padding-bottom: 3px;

  background: linear-gradient(to right, transparent, transparent), linear-gradient(to right, var(--link-underline-color), var(--link-underline-color));
  background-size: 100% 3px, 0 3px;
  background-position: 100% 100%, 0 100%;
  background-repeat: no-repeat;
  transition: background-size 500ms;
}

.link:hover {
  background-size: 0 3px, 100% 3px;
}

.button-standard {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;

  padding: 10px;
  padding-left: 11px;
  padding-right: 11px;
  background-color: rgba(255, 255, 255, 0.4);

  border-color: rgba(0, 0, 0, 0.14);
  border-width: 1px;
  border-style: solid;
  border-radius: 6px;
  text-decoration: none;
  color: #000000;

  box-sizing: border-box;
  box-shadow: 0px 3px 11px rgba(0, 0, 0, 0.07);
  font-size: 16px;
  font-weight: var(--header-font-weight);

  transition: all 0.15s ease;
}

.button-standard:visited {
  color: inherit;
}

.button-standard:hover {
  transform: scale(1.08);
  background-color: rgba(255, 255, 255, 0.7);
}

#section-1 {
  padding-top: 50px;
}

#app-store-buttons {
  display: flex;
  flex-direction: row;
  justify-content: center;
}

#app-store-buttons p {
  font-size: 24px;
  opacity: 0.1;
  line-height: 0%;
  padding: 15px;
}

.section-alignment {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

#landing-header {
  text-align: center;
  padding-top: 7px;
}

.main {
  max-width: 750px;
}

/* Mobile Only */
@media only screen and (max-width: 425px) {
  body {
    background-size: 1200%;
  }

  h2 {
    font-size: 36px;
  }

  p {
    font-size: 20px;
  }

  #app-store-buttons {
    display: contents;
  }
}

/* Mobile Design - Tablet */
@media only screen and (max-width: 999px) {
  body {
    background-size: 1200%;
  }

  /* Make sure to show the links once we're on a desktop */

  /* Make buttons stack instead */
/**/

  #app-store-buttons p {
    padding: 8px;
    visibility: hidden;
  }
}

/* Desktop Design */
@media only screen and (min-width: 1000px) {
  body {
    background-size: 700%;
  }

  /* Make sure to show the links once we're on a desktop */

  /* Push out the lists for better visibility */
}

textarea {
  padding: 10px;
  border-radius: 10px;
  background-color: rgba(255, 255, 255, 0.1);
  width: 80%;
  font-size: 16px;
  margin-top: 8px;
}

.optionsDiv {
  position: relative;
  /*Don't really need this just for demo styling*/

  float: left;
  min-width: 200px;
  margin-top: 20px;
  margin-left: 10px;
  margin-right: 10px;
}

.optionsDiv:after {
  content: '<>';
  font: 17px "Consolas", monospace;
  color: #333;
  -webkit-transform: rotate(90deg);
  -moz-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
  right: 11px;
  top: 14px;
  padding: 0 0 2px;
  border-bottom: 1px solid #999;
  position: absolute;
  pointer-events: none;
}

.optionsDiv select {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  max-width: 320px;
  height: 40px;
  float: right;
  margin: 5px 0px;
  padding: 0px 24px;
  font-size: 16px;
  line-height: 1.75;
  color: #333;
  background-color: rgba(255, 255, 255, 0.3);
  background-image: none;
  border: 1px solid #cccccc;
  -ms-word-break: normal;
  word-break: normal;
  border-radius: 6px;
}

#dropdowns {
  margin: 10px;
}

/* This it the input field when it does not have focus */
textarea[type=text] {
  outline: none;
  box-shadow: none;
  border: solid 1px rgb(91, 91, 91);
}

/* This is for the highlighted color when the input field is in focus */
textarea[type=text]:focus {
  outline: none;
  box-shadow: none;
  border: solid 1px rgb(125, 125, 125);
}

/* This it the input field when it does not have focus */
select {
  outline: none;
  box-shadow: none;
  border: solid 1px rgb(91, 91, 91);
}

/* This is for the highlighted color when the input field is in focus */
select:focus {
  outline: none;
  box-shadow: none;
  border: solid 1px rgb(125, 125, 125);
}

::-webkit-scrollbar {
  background-color: rgba(255, 255, 255, 0.4);
  width: 10px !important;
  border-radius: 10px;
}
</style>








  <div class="main">

    <!-- ----------------------------------------------------------------------- -->
    <!--                                Section 1                                -->
    <!-- ----------------------------------------------------------------------- -->
    <div id="section-1" class="section-alignment">

      <!-- Top content -->
      <h2 id="landing-header">Offline Tool for Text To Speech</h2>
      <div class="padding-semi-large"></div>


      <textarea type="text" id="textInput" rows="8" placeholder="Enter text here to speak it"></textarea>

      <div class="padding-semi-large"></div>

      <!-- -------------------------- App store buttons -------------------------- -->

      <div id="app-store-buttons">
        <button id="speakTextButton" class="button-standard" onclick="speakInputText()">Speak Text<img class="icon-link"
            src="https://cdn1.iconfinder.com/data/icons/user-experience/512/speak-256.png"></button>

        <p>|</p>

        <button id="pauseButton" class="button-standard" onclick="pauseSpeech()">Pause<img class="icon-link-small"
            src="https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-pause-512.png"></button>

        <p>|</p>

        <button class="button-standard" onclick="stopSpeech()">Stop<img class="icon-link-small"
            src="https://cdn3.iconfinder.com/data/icons/font-awesome-solid/512/stop-256.png"></button>

      </div>

      <div id="dropdowns">
        <div class="optionsDiv">
          <select name="voiceOptions" id="voiceOptions" onchange="changeVoice(this.value)">
            <option value="voice1">Daniel's voice</option>
            <option value="voice7">Samantha's voice</option>
            <option value="voice3">Alex's voice</option>
            <option value="voice6">Olivia's voice</option>
            <option value="voice2">Raj's voice</option>
            <option value="voice4">Fiona's voice</option>
            <option value="voice5">Fred's voice</option>
            <option value="voice8">Tessa's voice</option>
            <option value="voice9">Victoria's voice</option>
          </select>
        </div>

        <div class="optionsDiv">
          <select name="speedOptions" id="speedOptions" onchange="changeVoiceSpeed(this.value)">
            <option value="speed1">1x speed</option>
            <option value="speed0.75">0.75x speed</option>
            <option value="speed0.5">0.5x speed</option>
            <option value="speed1.25">1.25x speed</option>
            <option value="speed1.5">1.5x speed</option>
            <option value="speed1.75">1.75x speed</option>
            <option value="speed2">2x speed</option>

          </select>
        </div>
      </div>


    </div>

  </div>

  <script>


  // This is so that if speech is still playing from previous session, it stops on page load
speechSynthesis.cancel();

var isSpeaking = false;

// Initialize the speech synthesis
var speech = new SpeechSynthesisUtterance();
speech.rate = 1;
speech.pitch = 1;
speech.volume = 1;
speech.voice = speechSynthesis.getVoices()[0];

function speakInputText() {
  isSpeaking = true;

  speech.text = document.getElementById("textInput").value;
  speechSynthesis.speak(speech);
}

function pauseSpeech() {
  if (isSpeaking) {
    isSpeaking = false;
    speechSynthesis.pause();
    document.getElementById(
      "pauseButton"
    ).innerHTML = `Resume<img class="icon-link-small"
    src="https://cdn4.iconfinder.com/data/icons/defaulticon/icons/png/256x256/media-play-pause-resume.png">`;
  } else {
    isSpeaking = true;
    speechSynthesis.resume();
    document.getElementById(
      "pauseButton"
    ).innerHTML = `Pause<img class="icon-link-small"
    src="https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-pause-512.png">`;
  }
}

function stopSpeech() {
  isSpeaking = false;
  speechSynthesis.cancel();
}

function changeVoice(voice) {
  if (voice == "voice1") {
    // console.log((speech.voice = speechSynthesis.getVoices()[8]));
    speech.voice = speechSynthesis.getVoices()[8];
  } else if (voice == "voice2") {
    // console.log((speech.voice = speechSynthesis.getVoices()[0]));
    speech.voice = speechSynthesis.getVoices()[0];
  } else if (voice == "voice3") {
    // console.log((speech.voice = speechSynthesis.getVoices()[1]));
    speech.voice = speechSynthesis.getVoices()[1];
  } else if (voice == "voice4") {
    // console.log((speech.voice = speechSynthesis.getVoices()[11]));
    speech.voice = speechSynthesis.getVoices()[11];
  } else if (voice == "voice5") {
    // console.log((speech.voice = speechSynthesis.getVoices()[12]));
    speech.voice = speechSynthesis.getVoices()[12];
  } else if (voice == "voice6") {
    // console.log((speech.voice = speechSynthesis.getVoices()[18]));
    speech.voice = speechSynthesis.getVoices()[18];
  } else if (voice == "voice7") {
    // console.log((speech.voice = speechSynthesis.getVoices()[33]));
    speech.voice = speechSynthesis.getVoices()[33];
  } else if (voice == "voice8") {
    // console.log((speech.voice = speechSynthesis.getVoices()[37]));
    speech.voice = speechSynthesis.getVoices()[37];
  } else if (voice == "voice9") {
    // console.log((speech.voice = speechSynthesis.getVoices()[41]));
    speech.voice = speechSynthesis.getVoices()[41];
  }

  // for (let i = 0; i < 100; i++) {
  //   console.log((speech.voice = speechSynthesis.getVoices()[i]));
  // }
}

function changeVoiceSpeed(voiceSpeed) {
  // For some reason, speed below 0.5 doesn't work
  if (voiceSpeed == "speed2") {
    speech.rate = 2;
  } else if (voiceSpeed == "speed1.75") {
    speech.rate = 1.75;
  } else if (voiceSpeed == "speed1.5") {
    speech.rate = 1.5;
  } else if (voiceSpeed == "speed1.25") {
    speech.rate = 1.25;
  } else if (voiceSpeed == "speed1") {
    speech.rate = 1;
  } else if (voiceSpeed == "speed0.75") {
    speech.rate = 0.75;
  } else if (voiceSpeed == "speed0.5") {
    speech.rate = 0.5;
  }
}


  </script>



7. Conclusion

By following this guide, you can create and integrate a simple yet powerful Text-to-Speech converter tool on your Blogger site. It’s a great way to improve accessibility, engage your audience, and showcase your technical skills.

Have questions or feedback? Let us know in the comments!