Unlimited Wordpress themes, plugins, graphics & courses! Unlimited asset downloads! From $16.50/m
  1. Web Design
  2. JavaScript

How to Use JavaScript to Play Sound (Typewriter Effect)


Today, we’re going to create a typewriter effect using CSS and JavaScript. It will happen when a user hovers over a postcard image. And to push things further, we’ll use JavaScript to play a typing sound on the page and sync it with the letters as they appear.

Note: we’ll assume that this effect is for desktop screens only. Covering its functionality on mobile/touch screens is beyond the scope of this exercise. At the end of the tutorial, I’ll propose two ways for optimizing it for responsive scenarios.

Our JavaScript Typewriter Effect

Check out the final demo! Click the sound toggle to turn audio on, and hover over each postcard to see the typewriter effect in action.

1. Begin by Downloading the Page Assets

For this exercise, we’re going to need some assets.

The sound icon from iconmonstr
  • Then, an old typewriter typing sound effect from Mixkit.
The old typewriter typing sound from Mixkit
Merchant Ledger - Font Pack
Merchant Ledger - Font Pack

As a Pro member on CodePen, I’ll upload these files to the Asset Manager.

Need More Typewriter Fonts?

Envato Elements has a huge collection of typewriter and type fonts to help make this project your own. Subscribe today and get unlimited downloads!

typewriter web fonts on envato elements

2. Continue With the Page Markup

The page markup will consist of the following elements:

  • A div element that will contain a title and a button. A button class will determine if a sound will play each time we hover over an image. By default, the sound won’t play. To enable it, we have to click the button.
  • A div element that will contain four images along with their captions. By default, all captions will be invisible. Each one of them will appear as soon as we hover over the associated image. Lastly, ideally, they have to be short.
  • An audio element that will be responsible for embedding the sound on the page. Although optional, we’ll give it preload="auto" to inform browsers that it should load on page load.

Here’s the page markup:  

3. Define the Styles

Coming up next, we’ll discuss the most important aspects of our styles. For the sake of simplicity, as our main focus will be on JavaScript, we won’t cover the reset styles here. So, straight to the point:

  • We’ll use CSS Grid to create the layout for the two wrapper divs.
  • We’ll use the ::before pseudo-element of the toggle (sound) button to indicate that the sound is off. Initially, this will appear.
  • The image captions will be absolutely positioned elements and invisible by default. Depending on the image, they will appear either on its top or bottom.
  • All characters of each caption will appear sequentially on the image hover. This will be achieved thanks to the transition-delay property that we’ll add to them through JavaScript. However, they should simultaneously disappear when we stop hovering over an image.
  • We’ll add 4px spacing to the empty spans (characters) of each caption. So far our markup doesn’t contain spans. But soon enough, we’ll generate them through JavaScript.

Here are our main styles:

4. Add Interactivity

We’ll start by looping through all figures and for each one of them, several actions will take place:

Note: even safer, you might want to run these actions on page load (listen for the load event).

Modify the Captions’ Markup 

First, we’ll call the generateCharactersMarkup() function and pass to it the related figure element.

Here’s the function declaration:

Inside this function:

  • We’ll find the image caption and loop through its characters.
  • We’ll wrap each character around a span element.
  • We’ll check to see if the character is the first one or equal to space. 
  • If this isn’t the case, it will receive the transition-delay property. The value of this property will specify the amount of time to wait before showing the target character. In our example, each transition will occur after 150ms of the start of its previous one. In your projects, you can adjust this number via the sec variable.

So, if we start with this markup:

After executing the function, it will look as follows:

The generated markup

Notice that the first character and the spaces don’t receive an inline style.

Of course, instead of programmatically generating this markup, we could have added it by default on our HTML. But this will have two disadvantages. Firstly, it will bloat the HTML. Secondly, it will make its maintenance difficult in case any change is required.

Play Sound with JavaScript

At this point let’s put the sound in the loop.

Remember that it will be off by default.

The sound will be off from the beginning

Its state will be handled by the btn-sound-off CSS class and sound JavaScript flag.

Each time we click the button, both these will be updated. For instance, if the sound is on, the button won’t contain this class and the value of this flag will be true.

Here’s the related JavaScript code:

When the sound is on, it should play on image hover. But, for how long? That’s the thing we need to consider. Well, our demo audio file is pretty long, about 24 seconds. Obviously, we don’t want to play it all. Just a small part of it until the transition effect finishes.

To do so, we first have to calculate the duration of this effect. Taking that into account, we’ll then initialize a timer that will play the sound for this amount of time.

To better understand it, let’s go through the effect of the first image. If you check your browser console, you’ll notice that its last character has a 2.4 seconds delay. That means, the total effect will last 2.4 seconds (we don’t count the transition duration as it is almost zero). To keep the synchronization between the transition effect and audio playtime, we’ll play the first 2.4 seconds of the audio and then pause it.

For this implementation, we’ll use the mouseenter event. Here’s the declaration of its callback:

Consider in the code above the different ways we can use to calculate the audio duration.

On the other hand, the sound should pause and reset back to its initial position on mouse out.

For this implementation, we’ll use the mouseleave event. Here’s the declaration of its callback:


Phew, that’s all folks! Thank you for joining me on this long journey! We covered a lot of things today. Not only did we build a cool typing effect on hover, but also made it more realistic by synchronizing it with an old typewriter sound.

Here’s a reminder of what we built:

Touch and Mobile Devices

As we discussed in the introduction, this effect isn’t optimized for mobile/touch devices. Here are two possible solutions that you can try:

  • Disable the effect on these interfaces. For example, write some code for touch screen detection, and in that case, show the captions by default.
  • Oppositely, if you want to keep the effect for all devices, be sure to capture touch events.

Of course, depending on your needs, you can decouple the effect from the mouse events and keep it standalone or as a part of other events like the scroll one.

As the last thing, keep in mind that this effect might not work under all circumstances without extra customization. For example, as mentioned previously, the image captions should not be lengthy and split into multiple lines like this.

As always, thanks a lot for reading!

More JavaScript Tutorials on Tuts+

Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.