DEV Community

loading...
Cover image for Add vibration to your web applications

Add vibration to your web applications

aminnairi profile image Amin Updated on ・4 min read

Android & iOS applications are really powerful when it comes to user experience. You can use many hardware tools that come with your user's devices to play with — for instance — the camera, the accelerometer, or even the vibration.

But as the Web grows, so do the APIs that can communicate with those pieces of hardware.

Today, I'm going to show you how you can add vibration to enhance the user experience of your web applications using the Vibration API.

Goal

Our goal today is to create a function that will handle the vibration of the device used to display our application.

Since all devices are not equal in support, and some do not have a vibration chip at all like desktops, we should account for the case when the Vibration API is not supported. In our case, we won't throw any error or do anything special since I consider vibration as a bonus feature, not a requirement for using the application.

Let's code!

"use strict";

function vibrate() {
    if (!window) {
        return;
    }
}
Enter fullscreen mode Exit fullscreen mode

Since it is written in JavaScript, and that JavaScript can be run on the client but also on the server thanks to Node.js, we should account for the case when our script is run outside of a browser (by mistake I assume).

"use strict";

function vibrate() {
    if (!window) {
        return;
    }

    if (!window.navigator) {
        return;
    }
}
Enter fullscreen mode Exit fullscreen mode

If the navigator object is not available in the window global object, this means we are in serious trouble. But anyway, better be sure it is there before getting weird error messages.

"use strict";

function vibrate() {
    if (!window) {
        return;
    }

    if (!window.navigator) {
        return;
    }

    if (!window.navigator.vibrate) {
        return;
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, we check that the Vibration API is available. If it is not available, it is totally okay! This only means that the device does not have vibration capability. Since most of the time, this is not a big deal (except if you are trully relying on that feature for your application to work), we can simply stop the execution of our function if it is not available.

"use strict";

function vibrate() {
    if (!window) {
        return;
    }

    if (!window.navigator) {
        return;
    }

    if (!window.navigator.vibrate) {
        return;
    }

    window.navigator.vibrate(100);
}
Enter fullscreen mode Exit fullscreen mode

And there it is! The Vibration API in action. This is how we can tell the browser to vibrate the device for 100 milliseconds. You can even specify an array instead of a single value to create a vibration pattern.

For instance, if we need to vibrate two times for 200 milliseconds, separated by a 100 milliseconds interval, we can do that instead.

"use strict";

function vibrate() {
    if (!window) {
        return;
    }

    if (!window.navigator) {
        return;
    }

    if (!window.navigator.vibrate) {
        return;
    }

    window.navigator.vibrate([200, 100, 200]);
}
Enter fullscreen mode Exit fullscreen mode

See? That easy!

Parameterizing

You may want to customize the way the vibration happens in your application. Perhaps considering the user doing a specific action means a specific vibration. We should enable parameters for our function to make it more versatile.

"use strict";

function vibrate(options = { duration: 100, interval: 100, count: 1 }) {
    if (!window) {
        return;
    }

    if (!window.navigator) {
        return;
    }

    if (!window.navigator.vibrate) {
        return;
    }

    const pattern = [];

    for (let index = 0; index < options.count; index++) {
        pattern.push(options.duration);
        pattern.push(options.interval);
    }

    window.navigator.vibrate(pattern);
}
Enter fullscreen mode Exit fullscreen mode

That way, we can call our vibrate function like so.

<button
    onclick="vibrate({ duration: 200, interval: 150, count: 3 })">
    vibrate
</button>
Enter fullscreen mode Exit fullscreen mode

Hitting the button will trigger three vibrations of 200 milliseconds of duration separated by an interval of 150 milliseconds. Cool, huh?

Cleanup

That's it! Our function is now complete and we got the API we wanted. Now, as for any JavaScript function, we should make it more secure by adding some guards with some runtime type checking.

function vibrate(options = { duration: 100, interval: 100, count: 1 }) {
    if (arguments.length !== 1) {
        throw new Error("Expected exactly one argument.");
    }

    if (Object.prototype.toString.call(options) !== "[object Object]") {
        throw new TypeError("Expected first argument to be an object.");
    }

    if (typeof options.duration !== "number" || !Number.isInteger(options.duration)) {
        throw new TypeError("Expected options.duration to be an integer.");
    }

    if (typeof options.interval !== "number" || !Number.isInteger(options.interval)) {
        throw new TypeError("Expected options.interval to be an integer.");
    }

    if (typeof options.count !== "number" || !Number.isInteger(options.count)) {
        throw new TypeError("Expected options.count to be an integer.");
    }

    if (options.duration < 0) {
        throw new RangeError("Expected options.duration to be greater or equal to zero.");
    }

    if (options.interval < 0) {
        throw new RangeError("Expected options.interval to be greater or equal to zero.");
    }

    if (options.count < 0) {
        throw new RangeError("Expected options.count to be greater or equal to zero.");
    }

    if (!window) {
        return;
    }

    if (!window.navigator) {
        return;
    }

    if (!window.navigator.vibrate) {
        return;
    }

    const pattern = [];

    for (let index = 0; index < options.count; index++) {
        pattern.push(options.duration);
        pattern.push(options.interval);
    }

    window.navigator.vibrate(pattern);
}
Enter fullscreen mode Exit fullscreen mode

Yeah... It is a "little bit" longer. But what we are trying to do here is making sure the function gets called correctly, has the proper types for each one of the options and that they are all positive integers. If you don't like this type of programming habit, you can skip it and go back to our previous definition of the function but it is a good habit to have some runtime type checking since the developer-user can make mistakes (and so do we).

Conclusion

Yesterday, it was really hard to compete with native Android & iOS applications since the Web had little to no tools to communicate with the hardware, but it is a thing from the past.

Day after day, the browser's development team are working hard to bring those tools for the Web and we can now enjoy manipulating the Vibration API of the device right through our web applications.

Here is an example application to see if your device supports vibration.

Try it online.

Discussion (13)

pic
Editor guide
Collapse
oskarcodes profile image
Oskar Codes

Please note that this does not work on iOS devices.

Collapse
aminnairi profile image
Amin Author • Edited

Noted! They'll eventually support that feature but it is a shame that it gets its support later than the other platforms. 😞

But what is cool about that code is that you can use it today even if there's no support now because when it does you'll have literally nothing to do. It will just work!

Collapse
sunflower profile image
sunflowerseed • Edited

So does that mean if you want to try it, you'd have to find an Android phone to do it? (the only device that can do it is Android phone)

Collapse
aminnairi profile image
Amin Author

For now this is the case. I haven't any information about when will the Apple Dev Team (and other OEM) will decide to introduce this feature but one can say that this won't take long since this isn't an experimental feature anymore.

As for gaming platforms (Playstations, XBox, Steam) this may take even longer because they may not have the same roadmap for Web support than the other OEM.

Collapse
sunflower profile image
sunflowerseed

it is possible to condense it to

window && window.navigator && window.navigator.vibrate && window.navigator.vibrate([200, 100, 200]);
Collapse
alangdm profile image
Alan Dávalos

Or with optional chaining even better to

window?.navigator?.vibrate?.([200,100,200]);
Collapse
aminnairi profile image
Amin Author

Beware that this is still in experimental support! So if the browser does not support this syntax this will throw an error.

But I would of course use this syntax if I was using a transpirer for instance. Really shorten the syntax and looks nice!

Thread Thread
alangdm profile image
Alan Dávalos

Sure, then again the browsers that support vibrate and actually vibrate support it so for the most part it's harmless

Collapse
aminnairi profile image
Amin Author

Yes absolutely. From now I guess it's a matter of development practice. But this would work as well (I haven't test it though but it seems working to me).

Collapse
kayis profile image
K

I was so sad to find out that vibration was for mobile devices and not for Xbox controllers.

Collapse
aminnairi profile image
Amin Author

Oh shoot! I didn't know that one. Maybe Microsoft will push the support now that they decided to go on the path of choosing Chromium as their base for Edge. That's not impossible to see a better browser for the XBox in a near future.

I have hope!

Collapse
tamb profile image
Tamb

I can't get this to vibrate on my android. I don't get it. Is there a setting I need on?

Collapse
aminnairi profile image
Amin Author

There can be multiple reasons but this would mean that either your browser at this particular version does not support vibration or your device is not supported for this current version.

Try updating or changing your browser and try and check to see if there is an update for your device.

If you don't get it to work even after all of these steps then it must probably be that your device is not supported.