<!-- Works best in Chrome! -->
<div class="voiceinator">
<h1>The Voiceinator 5000</h1>
<select name="voice" id="voices">
<option value="">Select A Voice</option>
</select>
<label for="rate">Rate:</label>
<input name="rate" type="range" min="0" max="3" value="1" step="0.1">
<label for="pitch">Pitch:</label>
<input name="pitch" type="range" min="0" max="2" step="0.1">
<textarea name="text" placeholder="Start typing...">Hello! I love JavaScript 👍</textarea>
<button id="stop">Stop</button>
<button id="speak">Speak</button>
</div>
@import url('https://fonts.googleapis.com/css?family=PT+Sans');
html {
font-size: 10px;
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
margin: 0;
padding: 0;
font-family: 'PT Sans', sans-serif;
background-color: #d5d9e5;
color: #292b2c;
display: flex;
min-height: 100vh;
align-items: center;
}
.voiceinator {
padding: 2rem;
width: 50rem;
margin: 0 auto;
border-radius: 1rem;
position: relative;
background: #fff;
overflow: hidden;
z-index: 1;
box-shadow: 0 0 5px 5px rgba(0,0,0,0.1);
}
h1 {
width: calc(100% + 4rem);
margin: 0 0 2rem -2rem;
padding: .5rem;
text-align: center;
font-size: 4rem;
font-weight: 100;
font-family: 'PT Sans', sans-serif;
}
.voiceinator input,
.voiceinator button,
.voiceinator select,
.voiceinator textarea {
width: 100%;
display: block;
margin: 10px 0;
padding: 10px;
font-size: 2rem;
background: #fbfbfc;
outline: 0;
font-family: 'PT Sans', sans-serif;
border: 1px solid #c8c7cb;
border-radius: 2px;
}
label {
font-size: 2rem;
}
textarea {
height: 20rem;
}
.voiceinator button {
background: #72a3da;
color: #fff;
border: 0;
width: 49%;
float: left;
font-family: 'PT Sans', sans-serif;
margin-bottom: 0;
font-size: 2rem;
cursor: pointer;
position: relative;
}
.voiceinator button:active {
top: 2px;
}
.voiceinator button:nth-of-type(1) {
margin-right: 2%;
}
input[type=range] {
appearance: none;
border: 1px solid transparent;
padding-top: 8px;
background: #fff;
}
input[type=range]::slider-runnable-track {
height: 5px;
background: #e1e1e3;
border: none;
}
input[type=range]::slider-thumb {
appearance: none;
border: none;
height: 14px;
width: 14px;
border-radius: 50%;
background: #72a3da;
margin-top: -4px;
}
input[type=range]:focus {
outline: none;
}
input[type=range]:focus::slider-runnable-track {
background: #ccc;
}
input[type=range]::range-track {
height: 5px;
background: #e1e1e3;
border: none;
}
input[type=range]::range-thumb {
border: none;
height: 14px;
width: 14px;
border-radius: 50%;
background: #72a3da;
}
input[type=range]:focusring {
outline: 1px solid #dcdde2;
outline-offset: -1px;
}
.voiceinator select {
display: inline-block;
appearance: none;
appearance: none;
appearance: none;
outline: none;
background: #fbfbfc url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="%23c8c7cb" viewBox="0 0 20 20"><path d="M5 8l6 6 6-6z"/></svg>') right 5px center no-repeat;
padding: 10px 40px 10px 10px;
}
select::expand {
display: none;
}
const msg = new SpeechSynthesisUtterance();
let voices = [];
const voicesDropdown = document.querySelector('[name="voice"]');
const options = document.querySelectorAll('[type="range"], [name="text"]');
const speakButton = document.querySelector('#speak');
const stopButton = document.querySelector('#stop');
msg.text = document.querySelector('[name="text"]').value;
function populateVoices() {
voices = this.getVoices();
voicesDropdown.innerHTML = voices
.filter(voice => voice.lang.includes('en'))
.map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
.join('');
}
function setVoice() {
msg.voice = voices.find(voice => voice.name === this.value);
toggle();
}
function toggle(startOver = true) {
speechSynthesis.cancel();
if(startOver) {
speechSynthesis.speak(msg);
}
}
function setOption() {
console.log(this.name, this.value);
msg[this.name] = this.value;
toggle();
}
speechSynthesis.addEventListener('voiceschanged', populateVoices);
voicesDropdown.addEventListener('change', setVoice);
options.forEach(option => option.addEventListener('change', setOption));
speakButton.addEventListener('click', toggle);
stopButton.addEventListener('click', () => toggle(false));
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.