Thursday, 11 October, 2018 UTC


Summary

The web is an incredible place these days. New browser capabilities, paired with big improvements to the JavaScript language and advancements in development tools and frameworks, are changing the way we think about the web: from a place to read simple documents to a vast repository of great apps that rivals native platforms.
In fact, a lot of these new browser capabilities have to do with closing the gap between web and native apps, by providing new APIs that allow websites to do things like requesting geolocation information or sending push notifications, just like native apps do. Sam Bellen already covered these examples and some more in a previous article. In this one, we’re going to take a look at five more amazing things modern browsers can do.
Payment Request
Unless you’re building wildly creative websites, online multimedia experiences or web-based games, some new browser APIs can feel like they’re super fun but not so much useful for your daily work. Sure, it’s pretty cool that you can connect a gamepad to your browser, as we’ll see later, but you might also think that’s not going to help driving up conversion rates for your clients’ ecommerce sites (unless, you know, you’re building wildly creative ecommerce sites!). However the new Payment Request API proves that’s not always the case, and it can in fact help with those conversion rates. Let’s see how.
First-time users of ecommerce sites often face long and cumbersome checkout processes. These can be particularly painful in mobile devices, where typing is less comfortable and users’ attention is generally more divided. The Payment Request API allows developers to take advantage of a native user interface to ask for payment details, built into the browser itself. This not only provides a consistent experience to users, but can also make the process much easier and faster: users only need to enter their details once, and the browser will remember them for future payments, even for other sites. Moreover, it’s not unusual to find that a lot of the required information is already filled in in the first place, because browsers can extract it from previous form auto completion data.
You can see how this all looks in Chrome for desktop and Android in the screenshots below. If your browser supports this API (more about that later), you can check out the demo in my Magic Web web app.

Payment Request API example in Chrome for desktop

Payment Request API example in Chrome for Android
The basic usage of the API is very straightforward. First, we need a PaymentRequest instance:
const paymentRequest = new PaymentRequest(methods, details, options);
As you can see, the constructor accepts three parameters (named as methods, details and options variables in the example above). They hold all the information about the purchase, like a list of the things the user is going to pay for, total price and accepted payment methods:
const methods = [{
  supportedMethods: ['basic-card'],
  data: {
    supportedNetworks: ['visa', 'mastercard'],
  },
}];
const details = {
  displayItems: [
    {
      label: 'Nice t-shirt',
      amount: { currency: 'EUR', value: '35.00' },
    },
  ],
  total: {
    label: 'Total',
    amount: { currency: 'EUR', value: '35.00' },
  }
};
const options = {
  requestPayerName: true,
  requestPayerEmail: true
};
The API is very complete and there are a lot of optional keys in these objects, in order to ask for things like address or shipping options (and update prices accordingly on the fly). Please refer to the PaymentRequest documentation on MDN for more information.
Once our PaymentRequest instance is created, all we need to do is call its show method to let the browser know that it needs to display the payment UI. This returns a Promise that resolves to an object with the payment information, plus a complete method to tell the browser whether the payment was processed successfully, so that the UI can be updated:
paymentRequest.show()
  .then((result) => {
    // User confirmed info in payment UI
    callPaymentProvider(result).then(() => {
      // Payment successful
      result.complete('success');
    }).catch(error => {
      // Error processing payment
      result.complete('fail');
    });
  }).catch(() => {
    // User left payment UI
    result.complete('fail');
  });
Notice that the browser only takes care of collecting the payment information; the payment processing itself is up to you. In other words, you need to take that information and send it to your server or third party payment provider (think Stripe, for example). This is represented in the code above as a callPaymentProvider function.
The future of the Payment Request API looks very bright at the time of writing: latest versions of Chrome, Edge and Safari already support it, and it’s currently in development for Firefox.
Device Orientation
Wouldn’t it be cool if your page could react to a user shaking their device or rotating it? This is not only possible but actually quite easy to do thanks to DeviceMotion and DeviceOrientation events. Let’s see how they work.
These are events just like click or load, so we only need to add an event listener for them and handle the events whatever way we want. For example, to detect that the device is being shaken:
const SHAKING_ACCEL = 30;

window.addEventListener('devicemotion', event => {
  const {acceleration} = event;
  
  if (acceleration.x > SHAKING_ACCEL && acceleration.y > SHAKING_ACCEL) {
    console.log('Device being shaken');
  }
});
Or if we wanted to listen to the rotation of the device:
window.addEventListener('deviceorientation', event => {
  console.log(`Device rotated ${event.alpha} degrees`);
});
Take a look at the deviceorientation and devicemotion events documentation on MDN for additional details. Support for these events is very good, and they can be used confidently in all major mobile browsers.
Gamepad
We promised we’d see how to control the browser with a gamepad, and the time has come. The appropriately named Gamepad API allows us to do just that. The introduction of this browser capability opened the door for proper web-based games and other interactive experiences. Although it might be a little bit trickier to use than others, it’s still a nice API and you can get up and running with it in no time.
First, we get all the gamepads connected to the device. Let’s say we want to use the first one for this example.
const gamepads = navigator.getGamepads();
const gamepad = gamepads[0];
The gamepad variable is an object, the properties of which we can access to check what buttons are being pressed:
const {buttons, axes} = gamepad;

const indexOfButtonPressed = buttons.findIndex(button => button.pressed);

const isUpPressed = axes.y === -1;
const isDownPressed = axes.y === 1;
const isLeftPressed = axes.x === -1;
const isRightPressed = axes.x === 1;
But here’s the catch: if we want our page to react to button presses, we need to be constantly checking these properties, because there are no events for them. So how do we do that? The recommended and most performant way is to make use of requestAnimationFrame:
const logIfUpPressed = () => {
  if (buttons.axes.y === -1) {
    console.log('Up pressed');
  }
  
  requestAnimationFrame(logIfUpPressed);
};

logIfUpPressed();
The code above will call the logIfUpPressed function first, which will check whether the gamepad’s axis is pressed in the up direction. Then requestAnimationFrame will be called with the same function, which will schedule the function to be run in the next frame. The process will be repeated indefinitely, effectively checking the state of the gamepad every frame.
There are also events that we can listen to in order to trigger an action when a gamepad is connected or disconnected:
window.addEventListener('gamepadconnected', () => {
  console.log('Gamepad connected');
});

window.addEventListener('gamepaddisconnected', () => {
  console.log('Gamepad disconnected');
});
Although it’s not so well-known, this API has been around for quite some time, so all major modern browsers support it. There’s a basic demo in my Magic Web web app if you want to try it for yourself.

Connecting a gamepad in the Magic Web example
Shape Detection
One API that seems to have more creative uses at first sight is the Shape Detection API. It greatly simplifies the detection of faces in images in the browser, but it can also detect barcodes, so it really has some practical applications, too. This is something that can already be achieved with JavaScript (there are in fact some libraries that do it out there), but having an API for it means better performance and shipping less code to our users.
The Shape Detection API is extremely simple to use. First, we need an image:
const image = document.querySelector('img');
Then, we just instantiate a detector and call its detect method with the image:
const faceDetector = new FaceDetector();

faceDetector.detect(image).then(faces => {
  console.log(`There are ${faces.length} faces`);
});
As you can see, the detect method returns a Promise that resolves to an array of detected elements. Each of them is an object with information about the element detected, such as its boundaries, the eyes and the mouth position in the case of faces, or the code value for barcodes. Check the examples section in the Shape Detection API spec for more information.
The bad news about the Shape Detection API is that only Chrome supports it at the moment, and a feature flag needs to be activated for it. However, the API has been well received among developers, so there’s hope that it’ll be adopted by other browsers. If you want to try a simple demo, open Chrome and enable the feature flag by navigating to chrome://flags/#enable-experimental-web-platform-features, and then go to this demo in my Magic Web web app.

Testing the Shape Detection API in Magic Web
Web Bluetooth
We’re finishing this article with a pretty surprising API. The Web Bluetooth API allows websites to communicate with Bluetooth devices. That’s right, browsers can now directly connect to wireless devices, no extra software needed. And once again, it’s easier to do than you might think.
This is how to connect to a Bluetooth device and read its battery level:
navigator.bluetooth.requestDevice()
  .then(device => {
    console.log(`Selected device: ${device.name}`);
    return device.gatt.connect();
  })
  .then(server => server.getPrimaryService('battery_service'))
  .then(server => server.getCharacteristic('battery_level'))
  .then(characteristic => characteristic.readValue())
  .then(batteryLevel => {
    console.log(`Battery level is ${batteryLevel}`);
  });
When the requestDevice method is called, the user is presented with a list of nearby Bluetooth devices, so that one can be selected. That’s why the method returns a Promise, which resolves to the selected device. Then all that’s left to do is to connect to the device and get or set whatever values we want. There’s some jargon in the API coming from the Bluetooth specification, but you get the idea: the device values we want to read or write are called characteristics, which are grouped by services.
These are the basics of the API but there’s more to it; check out this article from Google’s Web Updates blog for a more in-depth introduction.
Just like the Shape Detection API, currently only Chrome supports the Web Bluetooth API and the same feature flag needs to be activated, unless you’re on Android or a Mac. Edge is considering implementing it, so better browser support might come in the future for this API.
If you happen to own a compatible Bluetooth light bulb, you can try a cool demo in my Magic Web web app that combines the Web Bluetooth API with DeviceMotion events to let you turn on and off a light bulb by shaking the device. There’s also a recording of me performing this demo live at a conference (in Spanish, but you can see the demo anyway).
Conclusion
I hope this article has showed you how incredibly powerful the web platform is today. Browsers can now do things we didn’t even dream of just a few years ago, and support for some of them starts to look surprisingly good. We can offer better and more innovative web experiences than ever to our users, experiences that feel closer to native apps while still benefiting from the ubiquity of the web. So please, go open your favourite editor and build something amazing!
The post 5 more things you didn’t know a browser could do! appeared first on Heart Internet Blog - Focusing on all aspects of the web.