DEV Community

loading...
Cover image for Sharing with the Navigator Share API

Sharing with the Navigator Share API

madsstoumann profile image Mads Stoumann ・3 min read

Four years ago, I read the article Does Anyone Use Social Sharing Buttons on 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 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

Let's write our own little "Sharing component", that can use regular, link-based sharing, if native sharing is not supported.

First, the markup:

<div
  data-share="device facebook twitter linkedin"
  data-share-label="Share on"
  data-share-device="Share using device sharing">
</div>
Enter fullscreen mode Exit fullscreen mode

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

And this is how it looks like if it doesn't:

sharingNoApi

JavaScript:

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);
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

A small helper-function is required:

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;
}
Enter fullscreen mode Exit fullscreen mode

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

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

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:

Thanks for reading!

Discussion (0)

pic
Editor guide