Cross-posted from my website's blog.
Progressive web apps (PWAs) are all the hype these days, and for good reason! PWAs provide significant user experience benefits over traditional web apps and web sites. If you're unfamiliar with the idea of a progressive web app, I'd recommend taking a look at this article on Google Developers.
The primary goal of PWAs is to blur the line between the UI/UX of web apps and that of native apps (apps that are built with native technologies to target specific operating systems, such as iOS and Android). One of the ways a PWA can blur this line is by providing the same, native-feeling functionality as a native app. Luckily for those of us trying to build great PWAs, browser vendors have been working hard to unlock these capabilities for us, including the ability to add to home screen, re-engage with push notifications, and even connect to a bluetooth device!
Shout out to all the great browser vendors out there for continuing to push the web platform forward!
This post will focus on a small piece of functionality that, when implemented properly, will enhance the native feel of your app and contribute to an enhanced user experience: sharing.
Sharing
In today's world, enabling your users to share your content effortlessly is more important than ever. But it doesn't only enhance their experience—when users are able to share your content easily across a wide range of platforms, the ultimate result is the increased visibility of your content. You benefit as well!
If you want to grow your audience and your reach, your content needs to be easy to share.
Traditionally, we web developers have been responsible for building custom share UIs into our web apps, either manually or by leveraging third-party libraries or services. For example, my website's blog utilizes several react-share buttons and icons for its custom share UI, as seen in the following video:
In the absence of alternatives, the custom share UI approach is great! However, it has a few major drawbacks:
- We have no way of knowing which share targets an individual user needs. Different users have different (often industry/domain-specific) sharing needs, and so we are forced to guess the list of most commonly needed share targets, such as Facebook, Twitter, Reddit, etc. As a fallback we sometimes enable users to copy a URL to their clipboard.
- Share UIs look different on different websites, forcing users to take a moment to understand the capabilities of the share UI on the site they are currently looking at. Furthermore, there is a frustrating disconnect for users that are accustomed to their device's native share UI.
- We are limited in the number of share targets we can support. For example, we cannot create a button that enables users to share content directly to a Facebook Messenger conversation.
- We have to build the UI ourselves or rely on a third-party library or service.
Is there a way we can solve all of these problems at once? There is! Please welcome to the stage the Web Share API!
The Web Share API
In 2016, the Chrome team first launched the Web Share API in Chrome 61 for Android. Since then, it has been picked up by a few more browsers (more on that to come). The Web Share API unlocks the power of the device's native sharing UI and makes it accessible to web apps.
Instead of web apps themselves being responsible for the share UI, the Web Share API enables a web app to instruct the browser to show the native share UI for a specific piece of shareable content.
This approach to showing share UIs solves all the problems mentioned above:
- The browser hands off the rendering of the share UI to the operating system (OS), which is aware of all of the installed apps that can act as share targets. The OS can then prioritize certain targets over others based on the user's sharing habits, their preferences, and the specific type of content being shared. Amazing!
- The user is presented with the same share UI that they are used to seeing in native contexts on their device.
- All of the installed apps that can act as share targets are shown as options in the native share UI.
- We don't have to build anything manually or rely on anything third-party. The browser and OS take care of everything!
Here's how it looks on my website's blog:
Browser Support
At the time of this writing, the Web Share API is implemented in a few mobile browsers but hasn't yet seen widespread adoption across both desktop and mobile. Check the Web Share API Can I Use page for up-to-date browser support information.
Because of poor browser support, it's best practice to use the Web Share API when it's available and fall back to a custom share UI when it isn't. I take this approach on my website. In the video above, notice how the native UI is triggered by the same button that would trigger the custom UI if Web Share were not supported. This approach is also taken by The Dev Community.
Because the Web Share API is so easy to use, adding it to your web app can be an extremely quick win UX-wise for users with Web Share support in their browser. Let's take a look at just how easy it is.
Using the Web Share API
Because all the hard work of building and showing the share UI has already been taken care of by the browser and OS, we have to do very little to enable our users to share content with Web Share. There are only two steps involved:
- Verify that Web Share is supported by the current browser
- If it is, tell it what to share!
When Web Share is supported, the browser exposes a share
function on the global window.navigator
object. The MDN docs do a great job of describing this function. Take a look!
All we need to do to check for Web Share is to check for the existence of this function:
if (navigator.share) {
// Web Share is supported
} else {
// Web Share is not supported
}
In order to mitigate abuse, browsers that support Web Share require navigator.share
to be called in response to a user gesture, such as clicking a share button:
myShareButton.addEventListener('click', () => {
if (navigator.share) {
// We can call navigator.share here!
}
})
// We can't call it here
The navigator.share
function expects you tell it what the user is trying to share. You specify this information as an object with a few optional keys: url
, text
, and title
. Although your requirements may be different depending on the nature of your app, most of the time you want to enable users to share the page they are currently looking at. To do this, you only need to define the url
and title
keys, which we have easy access to in a browser environment:
myShareButton.addEventListener('click', () => {
if (navigator.share) {
navigator.share({
url: location.href,
title: document.title
})
} else {
// Show custom share UI
}
})
Canonical URLs
If your app uses canonical URLs, you can query the document for a canonical URL and have that URL take priority over location.href
:
const canonicalLink = document.querySelector('link[rel=canonical]')
const url = canonicalLink ? canonicalLink.href : location.href
navigator.share({
url,
title: document.title
})
Reacting to the share
If your app needs to react to the share action, navigator.share
returns a promise for your convenience. The following example uses await
to handle the promise, but you can just as easily chain the usual .then()
and .catch()
calls.
try {
await navigator.share({ url, title })
console.log('Thanks for sharing!')
} catch (e) {
console.error('Could not share!', e)
}
That's pretty much all there is to it!
Summary
The Web Share API is the future of sharing on the web. Regardless of whether you consider your web app to be a PWA, it should use the Web Share API when it is available. It only takes a few lines of code to check for browser support and conditionally make a call to the API!
Beyond Web Share
It takes a lot of work to build a web app that is perceived by users as providing an equal or comparable experience to a native app. This checklist from Google enumerates an exhaustive list of PWA features, divided into baseline and exemplary feature categories.
Some of you may already be in the process of building new PWAs or migrating existing web apps to be PWAs. If that's you, don't let yourself be intimidated by the amount of work involved. Instead of focusing on the enormity of the entire task, prioritize features by anticipated impact, focus on one feature at a time, and identify and execute quick wins (such as Web Share!) in order to move your app in the right direction at an amplified rate. Don't forget to re-evaluate your priorities as you go!
Thanks for reading and happy coding!
Like this post?
Follow me on Twitter where I (re)tweet about frontend things: @worsnupd
Top comments (7)
Thank you a lot Daniel for this straightforward and very useful article. I am a backend engineer but I always love to learn browser capabilities about frontend at my free time. Good job!
Thanks,
Gerasimos Maropoulos. Author of iris-go.com
Glad you found it helpful! :)
Great write up on the Web Share API! I made a web component to make using web share even easier, check it out here and let me know what you think. It's actually how dev.to has implemented the share API too.
Thanks Phil! And nice web component! I like how it abstracts away the logic for checking for the Web Share API.
This is so cool. Thank you for this. For sure, I am using this in my next PWA.
You're welcome!
Works like a charm in my blog too..
Thanks for sharing!