The JavaScript Gamepad API has been around since 2012 and has solid support across most modern browsers. Chrome, Firefox, Safari, Edge, they've all got it.
The basic idea is simple: plug in a controller, and JavaScript can read button presses, joystick movements, and trigger values in real-time. This is the same API used whenever you play an online game or even when you stream gameplay through a browser.
But truth be told, outside of gaming on the browser, developers aren't really making much use of it just yet.
Quick Example
Here's the most basic example if you would like to test it out on your browser:
window.addEventListener("gamepadconnected", (e) => {
console.log("Controller connected:", e.gamepad.id);
});
function gameLoop() {
const gamepads = navigator.getGamepads();
for (let gamepad of gamepads) {
if (gamepad) {
// Button 0 is usually the main action button (A/X)
if (gamepad.buttons[0].pressed) {
console.log("Button pressed!");
}
// Left stick horizontal movement
if (Math.abs(gamepad.axes[0]) > 0.1) {
console.log("Moving left stick:", gamepad.axes[0]);
}
}
}
requestAnimationFrame(gameLoop);
}
gameLoop();
If you're browser supports the API, you'll see the following:

In this case you're seeing the gamepad.id
, which is the device name. Moving the left analog stick will yield the left sticks horizontal movement.

The stick position values range from -1 to 1, with -1 pointing to the left direction and 1 to the farthest right.
That's it. Plug in a controller, open the browser console, and start mashing buttons. It just works. I personally recommend (and use) the 8BitDo Ultimate controller for all gaming needs and it is what I'm using to test the examples on this page.
On most standard controller layouts, you can capture each button's pressed
status by referencing that button directly from the buttons
array of gamepad
.
For example, to see if the 'A' button is pressed you would do the following:
if (gamepad.buttons[0].pressed) {
console.log("Button pressed!");
}
Key mappings
Here are the indexes of standard gamepad button mappings:
0-3: Face buttons (A/Cross, B/Circle, X/Square, Y/Triangle)
4-5: Shoulder buttons (LB/L1, RB/R1)
6-7: Triggers (LT/L2, RT/R2)
8: Select/Back/Share
9: Start/Options/Menu
10-11: Stick clicks (L3, R3)
12-15: D-pad (up, down, left, right)
For the most part, most gaming controllers fall under the 'standard' flag. Non-standard controllers would be something like racing steering wheel controllers or flight sim controllers.
The API is surprisingly robust
What impressed me most is how well-designed the API is. Each gamepad exposes arrays of buttons and axes, with buttons giving you both pressed state and pressure values (for triggers). The axes handle joystick positions with proper dead zone considerations.
You get events for connection and disconnection, which means you can build interfaces that gracefully handle controllers being plugged in mid-session. The gamepad.mapping
property even tells you if it follows the "standard" layout, so you can make reasonable assumptions about which button does what.
// Check if it's a standard gamepad layout
if (gamepad.mapping === "standard") {
const jumpButton = gamepad.buttons[0]; // A/X button
const leftTrigger = gamepad.buttons[6]; // Left trigger
const rightStick = [gamepad.axes[2], gamepad.axes[3]]; // Right stick X/Y
}
You could technically build some pretty innovative user interfaces if you so wished.
Quick Demo
If you have a controller available, plug it in and test it out in the following grid card layout example:
I was actually surprised at how intuitive navigating this menu felt when I first built it out. Much like on a console menu, you naturally expect the cursor to move in a certain way and to load some submenu when selected with 'A'.
And it got me thinking about the current structure of most web pages. Most webpages are designed with small click-points, small text and scattered elements from top to bottom. This is just how we've gotten used to it for the most part. And it works great for a mouse, where you can near-instantaneously hop from one element to the next.
But with a controller, that same layout becomes a nightmare. You can't just jump to an element - you have to navigate to it sequentially. Suddenly, that tiny "Skip to main content" link at the top left, the nav menu stretched across the header, the sidebar on the right, the footer links at the bottom - it all becomes this tangled mess of "which direction do I go?"
A mouse thrives on chaos and density; a controller needs hierarchy and clear paths.
Once you start thinking with controllers though, interesting possibilities open up. Imagine using a gamepad to navigate through a photo gallery, left stick to move around, triggers to zoom, face buttons to like or share. Way more intuitive than trying to do the same thing with keyboard shortcuts.
Or picture giving presentations where you're not tied to clicking through slides on your laptop. Walk around the room with a wireless controller, use the D-pad for slide navigation, and triggers for pointer control.
For media sites, controllers are perfect. Play/pause, skip tracks, volume control, all the stuff that already maps perfectly to gamepad buttons.
But in order for this to happen, web developers and web designers will need to start to think differently. They'll need to start to think along the lines of game developers. Different elements might need to be grouped together into panels, new menus will need to built and normalized.
Instead of a dropdown menu, we might need a wheel with various options. A quick select if you will. Imagine opening up Netflix, holding the left analog stick down, and having your favorites pop up so that you can jump to them instantly. It's possible.
And just for the fun of it, if you do have a gaming controller currently, then press on the left analog stick for a quick example of what I mean. 😎
Conclusion
The Gamepad API represents something I really appreciate about the web platform. It quietly supports weird, niche use cases without making a big deal about it. Not every website needs gamepad support, but for the ones that do, it's incredibly powerful to have this capability built right into the browser.
It's also a reminder that the web is constantly expanding beyond its document-sharing origins. We now have APIs for accessing cameras, managing notifications, controlling audio, detecting device orientation, and yes, reading gamepad input. The browser has become an incredibly capable application platform, and most of us are only using a fraction of what's available.