JavaScript Web Share Table

PieceWhat it doesField note
navigator.share({ title, text, url })The OS share sheetThe native share dialog - apps the user installed appear
navigator.canShare(data)Feature detectChecks support AND the data shape - call before showing the button
{ files: [...] }Share filescanShare with files - images and docs join the sheet
User gesture requiredClick-gatedLike clipboard - share from a click handler, not on load
HTTPS onlyThe gateSecure contexts - same family as clipboard and camera
AbortError on cancelThe normal closeUser closing the sheet rejects - catch it, not a bug
vs copy-link buttonReach vs certaintyshare targets ANY app; clipboard is guaranteed but manual
Desktop fallbackProgressiveNo share support = hide the button or fall back to clipboard
Reference: the MDN Web Share API reference. navigator.share opens the OPERATING SYSTEM's share sheet: the same dialog native apps use, with every share target the user has installed - messengers, mail, notes. The contract matches the clipboard family: HTTPS, user-gesture-only, and canShare() checks both support and data shape before you show the button. Bottom line: files share too ({ files }), a user-closed sheet rejects with AbortError (catch it, it is normal), and the fallback for desktop-without-support is the clipboard copy - progressive enhancement in one feature check. Related tools: clipboard table (the fallback path), notifications table (the other gesture-gated family), and meta tags table (og: tags for the RECEIVING side of shares).

navigator.share opens the OPERATING SYSTEM's share sheet: the same dialog native apps use, with every share target the user has installed - messengers, mail, notes. One call replaces a grid of per-service share buttons.

Bottom line: the contract matches the clipboard family - HTTPS, user-gesture-only, and canShare() checks both support and the exact data shape (including files) before you show the button. A user-closed sheet rejects with AbortError: catch it, it is a normal close, not a bug.

The honest part: the OS picks the targets, not you - you cannot share TO a specific app, only offer the data and let the user choose. And desktop support is uneven, which is why the pattern is progressive: share button when canShare, clipboard copy when not.

How to use

  1. Gate the button: if (navigator.canShare?.({ url })) showShareButton() - canShare checks support AND data shape; hide rather than break on desktop.
  2. Share from a click: shareButton.onclick = () => navigator.share({ title, text, url }) - the gesture requirement is the same as clipboard's.
  3. Share files: navigator.canShare({ files }) then navigator.share({ files, title }) - images and documents join the sheet with the same contract.

Frequently asked questions

What does Web Share give that per-service share buttons do not?

The user's actual app inventory. Share-button grids hardcode services (Twitter, Facebook, WhatsApp...), leak those trackers to every page view, rot as services die, and cover maybe six of the twenty apps a user actually uses. navigator.share hands the data to the OS sheet, which lists every installed share target - including ones that did not exist when you shipped. The page also stops making third-party requests just to render buttons (privacy and performance). The trade: on desktop browsers without share support the button vanishes - which is why the fallback path (copy to clipboard with a toast) is part of the feature, not an afterthought.

What does canShare actually check that feature detection alone misses?

The data SHAPE. navigator.share existing does not mean every share type works on that platform - files, for example, are supported on fewer surfaces than text, and each platform validates the file types it accepts. canShare(data) returns whether THIS browser will accept THIS exact payload: canShare({ url }) versus canShare({ files }) can differ on the same device. The contract it enables: build the share payload, ask canShare, and only surface the share UI when the answer is true - otherwise the button shows and the share throws. It is the difference between feature detection (API exists) and capability detection (this call with this data will work).

Why is AbortError part of the design rather than an exception to handle specially?

Because closing the sheet IS a normal outcome. On mobile the share sheet is a modal UI; users open it and change their minds constantly - and the API reports that as a rejected promise with AbortError. Treating it as an error (logging, showing failure toasts) trains users that something broke when they simply cancelled. The pattern: await navigator.share(...) in try/catch, catch AbortError as a no-op, and only surface genuine errors (NotAllowedError for gestures, TypeError for bad data). The same philosophy appears across modern APIs - AbortController cancellations arrive as AbortError too - cancellation is a first-class outcome, not an exception.

How does Web Share relate to the og: meta tags?

They are the two ends of sharing. The og: tags (from the meta table) control what a link looks like when it arrives SOMEWHERE ELSE - the unfurled card in a chat or feed; they are read by the receiving platform's crawler. navigator.share is the ACTIVE path: the user taps share and picks a target from the sheet. A complete share story needs both: og: tags so shared LINKS unfurl beautifully anywhere, and Web Share so mobile users skip copy-paste entirely - the share sheet can even carry title, text and URL as structured data to targets that consume it directly. Sites with only share buttons and no og: tags produce broken-looking shares; sites with og: tags and no share button make mobile users do it manually.

Related tools