Pen Settings



CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource


Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource


Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.


Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.


  <script src="[email protected]"></script>
  <div id="root"></div>





                const en = "In recent years, governments around the world have been working to raise awareness about oral health. While many people have heard their teeth multiple times per day is a good habit, they most likely have not considered the reasons why this is crucial."
const RootComponent = {
  data () { return {
    sentence: en,
    text: setData(),    //initialization
    p: [],              //correct and incorrect
    showBackward: true, //show/hide the Back to previous button
    message: ''         //response
  template: `
    <p>Click the sentence, and you can listen to it:</p>
    <div @click="speak(sentence)">
        <span v-for="word in text.words">
          {{word+" "}}
        v-for="(option, index) in text.opt"
    <button v-show="showBackward" @click="backward">Back to previous</button>
  methods: {
    input(index) {
      this.text.optShow[index] = false;  //Hide the pressed button.
      //Replace the masked underline with the word you chose from the choices.
      this.text.words[this.text.mask[this.p.length]] = this.text.opt[index];
      this.text.record.push(index);   //Record the number of the button pressed.
      //If the string of the choice matches the that of the text, the answer is correct.
      if(this.text.optMask[index] == this.text.mask[this.p.length]) {
        //Add the string 'correct' to the array if it is correct
      } else {
        //If the answer is incorrect, add the string 'incorrect' to the array
      if(this.p.length == this.text.mask.length) {
        this.showBackward = false;  //Hide the "Back to previous" button.
        //Check if all elements of an array are correct.
        if(this.p.every(value => value == 'correct')) {
          this.message = 'All correct';
        } else {
          this.message = 'There are some errors.';
    speak(elem) {
      speechSynthesis.cancel();     //Cancel any audio that is playing.
      let uttr = new SpeechSynthesisUtterance();  //instance
      const voices = speechSynthesis.getVoices(); //Retrieving the voice list
      let voice;
      voices.forEach((elem) => {
        if( == 'Google US English') voice = elem;
      uttr.voice  = voice;          //Women's Voices
      uttr.volume = 1.0;            //Volume
      uttr.rate   = 0.8;            //Reading speed
      uttr.pitch  = 1.05;           //pitch
      uttr.lang   = 'en-US';        //language
      uttr.text   = elem;           //text
      speechSynthesis.speak(uttr);  //play
    backward() {
      if(this.p.length > 0) {
        //Delete the last element of the array and go back one.
        //Restore underlined words as they are entered
        this.text.words[this.text.mask[this.p.length]] = ' ____ ';
        //Show the button again.
        this.text.optShow[this.text.record.pop()] = true;
  mounted() {
    const uttr = new SpeechSynthesisUtterance();
    const voices = window.speechSynthesis.getVoices();
function setData() {
  let obj = {
    words: en.split(' '),   //Split the text into words.
    record: [],             //Record the order in which buttons are pressed.
    mask: [],               //Position of the word to mask
    opt: [],                //strings of buttons
    optMask: [],            //Position of the word the choice represents
    optShow: []             //Show/hide buttons
  let n = Array.from(Array(obj.words.length).keys()); //Array of sequential numbers
  for(let i = 0; i < 100; i++) {
    let a = Math.floor(Math.random() * n.length);
    let b = Math.floor(Math.random() * n.length);
    [n[a], n[b]] = [n[b], n[a]];
  //Number of words to mask: 1 word + 25% of the total
  let amount = 1 + Math.round(obj.words.length * 0.15);
  for(let i = 0; i < amount; i++) {
    obj.mask.push(n[i]);            //Add the position of the word to be masked
    obj.opt.push(obj.words[n[i]]);  //Add a string of choices.
    obj.optMask.push(n[i]);         //Add the position of the word the choice represents
    obj.optShow.push('true');       //Add button display
  obj.mask.sort((a, b) => a - b);
  //Replace masked words with underlines
  for(let i = 0; i < obj.opt.length; i++) {
    obj.words[obj.mask[i]] = ' ____ ';
  return obj;
const app = Vue.createApp(RootComponent);