How to Use the HTML5 Gamepad API (with complete examples)

gaberomualdo

Gabe Romualdo

Posted on December 15, 2020

How to Use the HTML5 Gamepad API (with complete examples)

The HTML5 Gamepad API is one of the more exciting HTML5 APIs in my opinion. It allows a website to pretty easily take input from a game controller that is connected to the user’s machine. The API supports hundreds of game controllers, both wireless and wired, including Xbox One controllers and PS4 controllers to name a few.

Before we begin, note that the gamepad API may not detect a gamepad until you press a button or move a stick on the controller. So, make sure to press some of the buttons when you test any sites or programs that use the Gamepad API.

Note: controllers and other game inputs are referred to as ‘gamepads’ throughout this article and in the gamepad API documentation.

Checking if Your Gamepad is Connected and Troubleshooting Potential Issues

To check if your gamepad is successfully connected, run navigator.getGamepads() in the JavaScript console and check if the result has a Gamepad object, and is not an array of null elements.

If your gamepad isn’t working with the API, here are a few things to try:

  • check if the device is connected to your machine via bluetooth, USB, or other method
  • try restarting your computer or web browser
  • try pressing some of the buttons or moving one of the sticks on the controller so that it is detected
  • try closing any other games or apps that are using the gamepad

Get a List of Connected Gamepads

The Gamepad API allows up to four gamepads to be connected at once.

To get an array of connected gamepads, use the navigator.getGamepads() method. The array is always of length four, where unused gamepad slots are null. The element(s) of connected gamepad(s) are Gamepad object(s). Here’s an example value of the navigator.getGamepads() method:

console.log(navigator.getGamepads());
// --> [Gamepad Object, null, null, null]
// Here, only one gamepad is connected, and the other three gamepad slots are null.
Enter fullscreen mode Exit fullscreen mode

Before trying to use a the functionality of the Gamepad API, make sure a gamepad is connected using the instructions in the previous section.

The Gamepad Object

The Gamepad object includes two important properties that are available in the vast majority of all gamepads and controllers: buttons and axes.

axes is an array of length four which represents the position of the left and right sticks in the gamepad. The first two elements in axes are the (x, y) coordinates of the position of the left stick, whereas the third and fourth elements in axes are the (x, y) coordinates of the position of the right stick. (x, y) values are numbers between -1 and 1 where the (0, 0) means the stick is has not moved.

In the horizontal axes (first and third elements in axes), -1 would indicate the stick is moved fully to the left, and 1 would mean the stick is moved fully to the right. In the vertical axes (second and fourth elements in axes), -1 would indicate the stick is moved fully to the top, and 1 would mean the stick is moved fully to the bottom.

Here’s an example value of axes with explanations in the comments:

setInterval(() => {
    const myGamepad = navigator.getGamepads()[0]; // use the first gamepad
    console.log(`Left stick at (${myGamepad.axes[0]}, ${myGamepad.axes[1]})` );
    console.log(`Right stick at (${myGamepad.axes[2]}, ${myGamepad.axes[3]})` );
}, 100) // print axes 10 times per second
Enter fullscreen mode Exit fullscreen mode

Contrary to buttons in HTML, event listeners cannot be added to gamepad buttons. Instead, you can check if a button is currently pressed by using the boolean pressed property in the element in the buttons array.

Here’s a list of button indexes are their Xbox and PS4 Equivalents in the HTML5 Gamepad API:

Index Button .pressed Code Button on Xbox Button on PlayStation
0 gamepad.buttons[0].pressed A X
1 gamepad.buttons[1].pressed B O
2 gamepad.buttons[2].pressed X Square
3 gamepad.buttons[3].pressed Y Triangle
4 gamepad.buttons[4].pressed LB L1
5 gamepad.buttons[5].pressed RB R1
6 gamepad.buttons[6].pressed LT L2
7 gamepad.buttons[7].pressed RT R2
8 gamepad.buttons[8].pressed Show Address Bar Share
9 gamepad.buttons[9].pressed Show Menu Options
10 gamepad.buttons[10].pressed Left Stick Pressed Left Stick Pressed
11 gamepad.buttons[11].pressed Right Stick Pressed Right Stick Pressed
12 gamepad.buttons[12].pressed Directional Up Directional Up
13 gamepad.buttons[13].pressed Directional Down Directional Down
14 gamepad.buttons[14].pressed Directional Left Directional Left
15 gamepad.buttons[15].pressed Directional Right Directional Right
16 gamepad.buttons[16].pressed Xbox Light-Up Logo PlayStation Logo

Here's an example of checking if Button One (A on Xbox, X on PS4) is pressed:

const myGamepad = navigator.getGamepads()[0]; // use the first gamepad

setInterval(() => {
    console.log(`Is Button One Pressed? ${myGamepad.buttons[0].pressed}`);
}, 1000 / 10) // check 10 times per second if the button one is pressed
Enter fullscreen mode Exit fullscreen mode

Detect When a Gamepad Has Been Connected

The name of the event when a gamepad has been connected to the user’s machine is gamepadconnected. The event argument that is passed into the event function includes a gamepad property, which is a Gamepad object for the gamepad the has been connected.

Instead of accessing this gamepad directly, it is more common to get the index of this gamepad in the navigator.getGamepads() array by using the Gamepad.index. For example:

// global gamepad object
let gamepadIndex;
window.addEventListener('gamepadconnected', (event) => {
    gamepadIndex = event.gamepad.index;
});

// now print the axes on the connected gamepad, for example: 
setInterval(() => {
    if(gamepadIndex !== undefined) {
        // a gamepad is connected and has an index
        const myGamepad = navigator.getGamepads()[gamepadIndex];
        console.log(`Left stick at (${myGamepad.axes[0]}, ${myGamepad.axes[1]})` );
        console.log(`Right stick at (${myGamepad.axes[2]}, ${myGamepad.axes[3]})` );
    }
}, 100) // print axes 10 times per second
Enter fullscreen mode Exit fullscreen mode

A More Complicated Example

Here's an example program that displays which buttons on a controller are pressed at a given time. Try running this code and pressing buttons on your gamepad; you should see that the indexes of the buttons that are pressed is displayed.

<body>
    <h1>No Controller Connected</h1>
</body>

<script type="text/javascript">
// global gamepad object
let gamepadIndex;
window.addEventListener('gamepadconnected', (event) => {
    gamepadIndex = event.gamepad.index;
});

setInterval(() => {
    if(gamepadIndex !== undefined) {
        // a gamepad is connected and has an index
        const myGamepad = navigator.getGamepads()[gamepadIndex];
        document.body.innerHTML = ""; // reset page
        myGamepad.buttons.map(e => e.pressed).forEach((isPressed, buttonIndex) => {
            if(isPressed) {
                // button is pressed; indicate this on the page
                document.body.innerHTML += `<h1>Button ${buttonIndex} is pressed</h1>`;
            }
        })
    }
}, 100) // print buttons that are pressed 10 times per second
</script>
Enter fullscreen mode Exit fullscreen mode

Browser Support

The HTML5 Gamepad API has complete support in most modern web browsers today. However, there are a few browsers that don't yet support it as of December 2020, including:

  • IE (11)
  • Opera Mini
  • Opera Mobile
  • Android Browser
  • KaiOS Browser

For more up-to-date information on browser support, see the Gamepad API's CanIUse Page.

To check if the browser supports the Gamepad API in JavaScript, the following code can be used:

const hasGamepadAPI = () => "getGamepads" in navigator;
Enter fullscreen mode Exit fullscreen mode

Conclusion

I hope this helps in learning how to use the HTML5 Gamepad API. While the API is not yet widely used in online games at the moment, it can still be useful for a number of projects and can be fun to try out.

Thanks for scrolling.

— Gabriel Romualdo, December 15, 2020

💖 💪 🙅 🚩
gaberomualdo
Gabe Romualdo

Posted on December 15, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related