Creating a Text-to-Speech Feature with HTML, CSS, and JavaScript
What Will We Build?
The app will include:
- A text input field where users can enter text.
- A dropdown to select from available voices.
- A button to convert the entered text into speech.
- A clean design with card styling and a modern UI.
Step 1: Setting Up the HTML
The HTML structure includes:
- A heading for the app title.
- A text area for input.
- A dropdown to list available voices.
- A button to trigger the speech.
Here’s the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Text to Speech</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="card">
<h1>Text to Speech</h1>
<textarea id="text-input" placeholder="Enter text here..."></textarea>
<select id="voice-select">
<option value="" disabled selected>Select a voice</option>
</select>
<button id="convert-btn">Convert to Speech</button>
</div>
<script src="script.js"></script>
</body>
</html>
Explanation:
- The
<textarea>
allows users to input text for conversion. - The
<select>
element is dynamically populated with voice options via JavaScript. - The button triggers the text-to-speech process.
Step 2: Styling with CSS
The CSS provides a polished look by centering the elements and adding a shadowed card design. The body uses a dark theme with a background color of #333
.
body {
font-family: Arial, sans-serif;
background-color: #333;
color: #ffffff;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.card {
background-color: #444;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
text-align: center;
max-width: 400px;
width: 100%;
}
h1 {
margin-bottom: 20px;
}
textarea {
width: 95%;
height: 100px;
resize: none;
}
textarea, select {
margin-bottom: 15px;
padding: 10px;
border: none;
border-radius: 5px;
font-size: 16px;
background-color: #555;
color: #fff;
}
textarea::placeholder {
color: #bbb;
}
select {
width: 100%;
}
button {
width: 100%;
padding: 10px;
background-color: #28a745;
border: none;
border-radius: 5px;
font-size: 18px;
color: #ffffff;
cursor: pointer;
}
button:hover {
background-color: #218838;
}
Explanation:
- Card Design: The
.card
class centers the content with padding, rounded corners, and a shadow. - Responsive Inputs:
textarea
andselect
fill the card width, ensuring usability on all screen sizes.
Step 3: JavaScript for Text-to-Speech Functionality
The JavaScript leverages the Web Speech API’s speechSynthesis to handle text-to-speech conversion. It also filters voices for Google Chrome-supported languages.
const textInput = document.getElementById('text-input');
const voiceSelect = document.getElementById('voice-select');
const convertBtn = document.getElementById('convert-btn');
// List of languages supported reliably in Chrome
const supportedLanguages = [
'en', // English
'es', // Spanish
'fr', // French
'de', // German
'it', // Italian
'ja', // Japanese
'ko', // Korean
'zh', // Chinese
'ru', // Russian
'pt', // Portuguese
'hi', // Hindi
];
// Populate the voice list
function populateVoices() {
const voices = speechSynthesis.getVoices();
const filteredVoices = voices.filter(voice =>
supportedLanguages.some(lang => voice.lang.startsWith(lang))
);
if (filteredVoices.length === 0) {
console.error('No voices available for supported languages.');
voiceSelect.innerHTML = `<option value="" disabled>No voices available</option>`;
return;
}
voiceSelect.innerHTML = filteredVoices
.map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
.join('');
}
// Fetch and populate voices
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = populateVoices;
}
populateVoices();
// Convert text to speech
convertBtn.addEventListener('click', () => {
const text = textInput.value.trim();
const selectedVoiceName = voiceSelect.value;
if (!text) {
alert('Please enter some text.');
return;
}
if (!selectedVoiceName) {
alert('Please select a voice.');
return;
}
const voices = speechSynthesis.getVoices();
const selectedVoice = voices.find(voice => voice.name === selectedVoiceName);
if (!selectedVoice) {
alert('Selected voice is not available.');
return;
}
const utterance = new SpeechSynthesisUtterance(text);
utterance.voice = selectedVoice;
// Speak the text
speechSynthesis.cancel(); // Clear any queued speech
speechSynthesis.speak(utterance);
});
Explanation:
1. Filter Supported Voices:
- The
supportedLanguages
array ensures only Chrome-compatible languages are included in the dropdown.
2. Populate Voice List:
- The
populateVoices()
function retrieves and filters the available voices, displaying them dynamically in the<select>
dropdown.
3. Handle Speech Conversion:
- When the button is clicked, the app retrieves the text and selected voice, creates a
SpeechSynthesisUtterance
, and plays the audio usingspeechSynthesis.speak()
.
Enhancements for Real-World Use
- Mobile Compatibility: Test on mobile browsers to ensure voice lists load correctly.
- Custom Error Handling: Inform users if no voices are available or if speech fails.
- Dynamic Updates: Automatically refresh the voice list if a new voice pack is installed.
Conclusion
With this project, you’ve created a functional text-to-speech app that works seamlessly with Google Chrome-supported voices. It’s an excellent starting point for adding accessibility features or enhancing user interaction on your website. Try deploying it and explore how users engage with this feature!