loading...
Cover image for Native "tap to share" in JavaScript with the Web Share API: Current status, tips, and limitations.

Native "tap to share" in JavaScript with the Web Share API: Current status, tips, and limitations.

macargnelutti profile image Matteo Cargnelutti Updated on ・4 min read

"This specification (Web Share API) defines an API for sharing text, links and other content to an arbitrary destination of the user's choice."

While the official Web Share API definition does not sound too exciting, this new feature actually offers a solution to a problem web developers have been facing for a decade.
This new API provides a way of using the native "share" feature of the browser or operating system via JavaScript, allowing users to seamlessly share a piece of content from the browser the same way they would from a native application.

No more need for (often) bloated and (sometimes) nosey third-party share "plugins" and their endless lists of social media icons? Well, we are not quite there yet, but let's see how we can already use this new Web API to our advantage.


How does it work?

This API consists in two methods that were added to the navigator object, share() and canShare(). Both receive a ShareData dictionary, containing information to share from the current page to another service, picked by the user from their installed apps list.

It is important to note that, because they are sensitive by nature, none of these methods can be used on a non-HTTPS web page. While implementations may vary, this aspect is part of the specification.

Sharing

The nature of the dictionary that navigator.share() uses, called ShareData, is pre-defined as to ensure interoperability, and looks as follow:

const toShare = {
  title: "@macargnelutti on dev.to",
  text: "Have a look at my posts on dev.to!",
  url: "https://dev.to/macargnelutti/"
};

The ShareData object - in theory - cannot hold anything besides title, text and url. However, the current specification does not suggest a limited length for text, and it is therefore likely possible to pass stringified JSON or base64-encoded content to it. Whether it's a good idea or not is a whole other debate (Spoiler alert: it's probably not).

navigator.share, which takes this dictionary as a parameter, returns a Promise that will be pending while the user makes their choice.

const button = document.querySelector('button');
button.addEventListener('click', async () => {
  try {
    await navigator.share(toShare); // Will trigger the native "share" feature
    button.textContent = 'Shared !';
  }
  catch(err) {
    button.textContent = 'Something went wrong'; 
    console.log(err);
  }
});

The Web Share API at work on mobile and desktop

Interestingly, it appears to be possible to distinguish an exception that arose because the share feature failed or because the user cancelled the action: Safari currently raises an AbortError upon cancellation.

Safari raises an AbortError exception upon cancelation of navigator.share

In addition, part of the early Web Share API Level 2 specification draft, the navigator.canShare method allows to make sure a ShareData dictionary is suitable for sharing before making a request.

This comes in handy to navigate between implementations of the Web Share API: for example, Google's current implementation of the API allows for sharing files via a files attribute, which is part of the latest Community Draft for Web Share API level 2 but not of the latest Web Share API level 1 Working Draft, as mentioned earlier.

Using canShare makes a lot of sense in that context.

const toShare = {
  title: "Viruses in a trench coat",
  text: "Definitely not 5 viruses in a trench coat",
  files: [...]
}

if (navigator.canShare(toShare)) {
  console.log('We can use the Web Share API to share this.');
}

Receiving shared data in your PWA

Through the very experimental Web Share Target API, it is possible to build progressive web apps able to receive that type of information simply by using manifest.json, which makes the Web Share API all the more powerful.

I recommend Google's Web.dev guide on the topic.


Current status and limitations

While in the works since 2016 and still experimental, the standardization process of that feature seems to be making good progress, with a first public working draft released last December.

Current support for navigator.share makes it more than usable on mobile, with iOS Safari, Chrome for Android and Samsung Internet already Web Share-ready, according to caniuse.com.

navigator.share support report on caniuse.com

Support for navigator.canShare is much more limited, as only Chrome for Android supports it at the moment.

navigator.canShare support report on caniuse.com

As usual, progressive enhancement is key here to start using these new features:

  • Make sure navigator.share exists before using it
  • Have a proper fallback for this feature in case it's not available

Exception thrown by navigator.share not being implemtended


The Web Share API is one of these features that helps breaking the barriers between web and native and that, while still in the works, can bring immediate improvement to how users experience the products we build: use responsibly, but surely use it πŸŽ‰.

Posted on by:

macargnelutti profile

Matteo Cargnelutti

@macargnelutti

CTO & Software Developer at Grafton Studio, Boston MA. Interested in everything Web standards, Python, Javascript. He/Him, πŸ‡ΊπŸ‡ΈπŸ‡«πŸ‡·. Opinions are my own.

Discussion

pic
Editor guide
 

Did you notice that DEV uses the web share API? πŸ˜ƒ

 

Ah ah good point ! I didn't even notice !

 

I'm being a bit cheeky, only because I implemented it myself.

You might be interested in how though, I've built a web component that can wrap around traditional share links and take over if the web share API is available. It's called <web-share-wrapper> and I'd love your opinion on it.

Just had a look. I think that is a great solution and a very good example of progressive enhancement. Well done 🎩!

 

Hi ! Thank you for this article. I have a question. I'm implementing this feature on a web page. I've noticed that all fields are well filled in android (title, text, url) but not in iOS. In Apple mail for example, object isn't filled, on Facebook Messenger, text isn't filled. Do you know if there is a solution for that ?
Thank you

 

Fun game: count how many social media from the cover pic have disappeared since the picture was taken.