Web Share API - Progressively enhanced web component
How I implemented a share button at the bottom of my blog posts on this site using the Web Share API and web components. Scroll to the bottom and see if your browser supports the Web Share API... You'll see a share button.
Being able to hook into native functionality when its available is a great especially when you are able to do it in a progressively enhanced manner. A great example of this is the Web Share API. It is quite a new API that is still in working draft at the W3C. Even though it is still in working draft and not a common API available on all browsers. The main point is that it is available on some browsers. This allows you to start using it, and by allow the users of those devices and browsers to have an extra feature available to them. Aka - Progressive enhancement. While this allows you to use a new feature, its also a way for browsers and the W3C to get people testing the features, get excited and for it to become more than a working draft.
As with all technical web docs, a great starting point is MDN Web Docs, and the docs for the Web Share API is no different. The API is exposed to you via JavaScript as Navigator.share().
Broken down the Web Share API is one asynchronous method call, if its available in the users browsers. The function takes an object containing the data to share.
navigator.share({});
The data you pass to the function is
- url - A URL string referring to a resource being shared
- title - The title of the document being shared. May be ignored by the target
- text - Arbitrary text that forms the body of the message being shared. (not used in my examples)
- files - Files to be shared (not covered in this post)
In its most basic example you can just pass the url and title to the share()
method and it will work for supported browsers. (Try copy and pasting the following into console of dev tools of a supported browser).
navigator.share({
url: "http://matthewroach.me/web-share-api-progressively-enhanced-web-component/",
title: "Web Share API - Progressively enhanced web component",
});
While this is all great and all, I've mentioned progressively enhanced quite a few times already, and that this API is not available in all browsers. Being able to implement this as an enhanced feature is very neat, and if you pair it with web components you can have a fully isolated and truly enhanced feature for some of your users. Web components (customElements) pairs well here as they are available in the browsers that have support for the Web Share API.
The button
We are dealing with an action, so we use a button
, and as the button should only be shown if the browser supports the Web Share API its default state is hidden
. As the Web Share API is a JavaScript based API and we can only detect it in the users browser we will control the visibility of the button via JavaScript. This also means if you are browsing without JavaScript enabled you are none the wiser.
<button
hidden
is="s-hare"
a-title="Web Share API - Progressively enhanced web component"
a-url="http://matthewroach.me/web-share-api-progressively-enhanced-web-component/"
>
Share
</button>
You maybe wondering what the extra attributes on the button are. the is
and the a-title
and a-url
are.
- The
is
global HTML attribute: Allows you to specify that a standard HTML element should behave like a registered custom built-in element. - The
a-title
anda-url
are custom attributes I decided to use for the component to read them for when the share API is called. Remember from above to share you need a url and title passed to the method.
The JavaScript
All the code that makes the button.. Pop.. Or well work in situations where it is able to. The progressive enhanced experience.
Below is the full JavaScript class and custom element define call to set up the button code from above to work.. Side note, view source to see it on my site.
As I used the is
attribute on the button
element our class extends the HTMLButtonElement
In the constructor
I call a class method canWebShare
- if this returns false. Browsers that don't support the Web Share API nothing more happens. But if your browsers has the Web Share API available navigator.share
, the code will call showButton
which actually shows the button and adds a click event listener to it.
Accessibility Tip: As I have extended the native HTML button
you only need to set up the click event as the button element will fire this event when the user uses either the enter or space key on their keyboard. It will also catch the mouse click event too.
Now the event listener is added the button is all set for user interaction, and this is where the a-title
and a-url
attributes come into play. When a user activates the button the event listener function will use the values of these attributes to pass the data to the navigator.share
method. Remember this method call returns a promise, you can use await
here.. And guess what no need to polyfil for this as the browsers that support Web Share also support await
The share dialog is part of the users operating system (OS) and from when the user clicks the button you have passed the share off to the OS.
class Share extends HTMLButtonElement {
constructor() {
// Always call super first in constructor
self = super();
if (this.canWebShare()) {
this.showButton();
}
}
canWebShare() {
return navigator.share !== undefined;
}
showButton() {
self.removeAttribute("hidden");
self.addEventListener("click", self.shareEvent);
}
async shareEvent() {
try {
await navigator.share(self.shareData());
} catch (err) {
alert("Sorry, sharing failed - you could try again");
}
}
shareData() {
const shareData = {
title: self.getAttribute("a-title"),
url: self.getAttribute("a-url") || window.location.href,
};
if (self.getAttribute("a-text")) {
shareData.text = self.getAttribute("a-text");
}
return shareData;
}
}
customElements.define("s-hare", Share, { extends: "button" });