Sharing with the Navigator Share API
Tags: html, javascript, css, codepen
Published: 2021-03-10 13:35:40

Four years ago, I read the article [Does Anyone Use Social Sharing Buttons on Mobile?](https://www.moovweb.com/post/anyone-use-social-sharing-buttons-mobile)

The result was shocking: *Only 0.2% of users ever click on a mobile sharing button!* Yet, most clients I've worked for, insist on having sharing buttons on almost all pages.

But, here's the thing: **Users like being in control.** Maybe they don't like Twitter or Facebook, but prefers Instagram, Slack or Teams — or something else entirely.

Why not give them control, and let them decide themselves which platform to share to?

This is where the [navigator.share](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share) api comes in handy. It will use the native sharing of the user's device.

Browser support isn't *that* great on desktop devices, but on mobile devices, the support is OK:

![Webshare api](https://dev-to-uploads.s3.amazonaws.com/i/9nd7tpo9j0id2kq5ewyd.png)
 
Let's write our own little "Sharing component", that can use regular, link-based sharing, if native sharing is not supported.


First, the markup:

```html
<div
  data-share="device facebook twitter linkedin"
  data-share-label="Share on"
  data-share-device="Share using device sharing">
</div>
```

This tells the script that we want to use **device**-sharing (aka native sharing), but it should fallback to link to Facebook, Twitter and LinkedIn, if native sharing is **not** supported.

The `data-share-label` will be added as an `aria-label` to all fallback-links, while the `data-share-device` will be added to the icon for native sharing.

This is how it looks like on a device supporting native sharing:

![Share API Supported](https://dev-to-uploads.s3.amazonaws.com/i/tfv06tec3z6v4ha69tox.jpg)
 
And this is how it looks like if it doesn't:

![sharingNoApi](https://dev-to-uploads.s3.amazonaws.com/i/dbnivpmvkut0gs8bdnrc.png)

*JavaScript:*

```js
export function Share(element) {
  const canShare = 'share' in window.navigator;
  const options = element.dataset.share.split(' ');
  const shareIndex = options.findIndex(option => { return option === 'device' });
  const shareData = {
    facebook: { url: 'https://www.facebook.com/share.php?u=' },
    linkedin: { url: 'https://www.linkedin.com/shareArticle?mini=true&url' },
    twitter: { url: 'https://www.twitter.com/share?url=' }
  }

  if (shareIndex > -1 && !canShare) {
    options.splice(shareIndex, 1);
  }

  if (shareIndex > -1 && canShare) {
    const shareButton = h('button', {
      'aria-label': `${element.dataset.shareDevice}`,
      'data-share-item': ''
    }, [h('i')]);
    shareButton.addEventListener('click', () => {
      navigator.share({
        title: document.title,
        url: location.href
      }).catch(() => { return });
    })
    element.appendChild(shareButton);
  }
  else {
    options.forEach(option => {
      const shareLink = h('a', {
        'aria-label': `${element.dataset.shareLabel} ${option}`,
        'data-share-item': option,
        href: shareData[option].url + encodeURIComponent(location.href),
        rel: 'noopener noreferrer',
        target: '_blank'
      }, [h('i')])
      element.appendChild(shareLink);
    })
  }
}
```

A small helper-function is required:

```javascript
function h(type, attributes, children = []) {
  const element = document.createElement(type);
  for (let key in attributes) {
    element.setAttribute(key, attributes[key]);
  }
  if (children.length) {
    children.forEach(child => {
      if (typeof child === 'string') {
        element.appendChild(document.createTextNode(child));
      } else {
        element.appendChild(child);
      }
    });
  }
  return element;
}
```

And finally, to init the share-component/s:

```javascript
const shares = document.querySelectorAll(`[data-share]`);
shares.forEach(element => {
  Share(element);
});
```

---
## Codepen Demo
If your browser supports `navigator.share`, (for instance Safari on both Mac/iOS) you'll see the single share-icon below, otherwise the fallback with three icons:

{% codepen https://codepen.io/stoumann/pen/eYBQbPj %}

Thanks for reading!