Skip to content

Capabilities · API

Web Share API

Published

Behind a flagFlag required in Firefox (Desktop)W3C

navigator.share() hands a URL, title, text, or files to the operating system’s share sheet, so a PWA can send content to any app the user has installed without building its own share menu. navigator.canShare() validates the same payload synchronously and, unlike share(), works without a user gesture.

On desktop the API is partial: Chrome 89 and Edge 81 implement it on Windows and ChromeOS only (Chromium bugs 40542648 and 40729163 track macOS and Linux), Firefox 71 keeps it behind the dom.webshare.enabled preference, and Android WebView has no implementation (crbug.com/40540400). Safari 12.1 on macOS and 12.2 on iOS, Chrome 61 and Firefox 79 on Android support it without caveats.

navigator.share()
navigator.share(data)
navigator.canShare()
navigator.canShare(data)

share() returns a Promise<undefined> that resolves once the data has been transmitted to the chosen target, or to the OS when the target cannot confirm receipt. canShare() returns a boolean and is the only one of the two that may be called outside a user-activation handler. Both are [SecureContext]: on http:// origins other than localhost, navigator.share is undefined.

Both methods take one optional data argument, a ShareData dictionary. Every member is optional on its own, but the dictionary must carry at least one of title, text, url, or a non-empty files; otherwise validation fails.

Member Type Required Description
title USVString No Title of the shared content. Mail targets use it as the subject; many messaging targets discard it.
text USVString No Free-form body text, sent alongside or instead of url.
url USVString No Absolute or relative URL, resolved against the document’s base URL before sharing; "" shares the current page. Only http:, https:, and schemes the browser safelists are sharable.
files sequence<File> No Files to share. { files: [] } with no other member is treated as an empty dictionary; { text: "x", files: [] } is accepted and the empty list ignored.

Members the browser does not recognise are dropped silently (WebIDL dictionary semantics), so a browser that only knows title, text, and url will share those three and ignore files. Pass each member to canShare() on its own when you need to know that every one is supported.

share() rejects its promise with one of the following DOMException names. The order below is the order the specification’s algorithm checks them in.

Exception Condition
InvalidStateError The document is not fully active, or an earlier share() promise is still pending ([[sharePromise]] is not null). Chromium skips the second check on Android.
NotAllowedError The web-share Permissions Policy denies the document (default allowlist is 'self', so a cross-origin iframe needs allow="web-share"); or the call has no transient user activation; or a file type is blocked for security reasons.
TypeError “Validate share data” returned false: no member present; url fails to parse; url uses a local scheme, file:, javascript:, ws:, wss:, or any scheme that is not sharable; files is present but the browser does not support file sharing or judges a file potentially hostile.
AbortError No share targets are available, or the user dismissed the share sheet.
DataError The chosen target failed to start, or transmitting the data to it failed.

canShare() throws nothing. It returns false for exactly the conditions that make share() reject with TypeError, and true otherwise, including when share() would later reject with AbortError because the user cancels (see the canShare() algorithm (w3.org)).

Each example feature-detects first and shows what runs when support is absent. All three must be triggered from a user-activation handler such as click.

Sharing the current page with a clipboard fallback

Section titled “Sharing the current page with a clipboard fallback”

Detect navigator.share before wiring the button; when it is missing (Firefox desktop with the preference off, Android WebView, any http:// origin) copy the URL instead and tell the user what happened. The share call itself must stay inside the click handler so the transient activation is still valid when share() runs.

const button = document.querySelector('#share');
button.addEventListener('click', async () => {
const payload = { title: document.title, url: location.href };
if (!navigator.share) {
await navigator.clipboard.writeText(location.href);
button.textContent = 'Link copied';
return;
}
try {
await navigator.share(payload);
} catch (err) {
if (err.name === 'AbortError') return; // user closed the sheet
console.error(`${err.name}: ${err.message}`);
}
});

Awaiting anything (an analytics call, a fetch) before share() is the usual way to lose the activation; do the share first and record the event after the promise resolves.

Sharing a generated text file only when canShare() accepts it

Section titled “Sharing a generated text file only when canShare() accepts it”

File sharing is narrower than URL sharing: Chrome 76 on Android added it, desktop Chrome 89 shares files on Windows and ChromeOS only, Safari 14 added files, and Firefox has no file sharing in any version (BCD api.Navigator.share.data_files_parameter). Build the File, ask canShare() whether this browser will take it, and fall back to a download link when it will not.

async function shareReport(csvText) {
const file = new File([csvText], 'report.csv', { type: 'text/csv' });
if (navigator.canShare?.({ files: [file] })) {
try {
await navigator.share({ files: [file], title: 'Report' });
} catch (err) {
if (err.name !== 'AbortError') throw err;
}
return;
}
const link = document.createElement('a');
link.href = URL.createObjectURL(file);
link.download = file.name;
link.click();
URL.revokeObjectURL(link.href);
}

canShare({ files }) returns false both when the browser cannot share files at all and when it rejects this particular file, so the fallback covers both without separate checks.

Checking each member before a multi-member share

Section titled “Checking each member before a multi-member share”

Because unknown members are ignored rather than rejected, a browser that lacks files support will still resolve a share({ text, files }) call, having shared only the text. Validate member by member when a partial share would mislead the user.

function supportedMembers(data) {
if (!navigator.canShare) return [];
return Object.entries(data)
.filter(([key, value]) => navigator.canShare({ [key]: value }))
.map(([key]) => key);
}
const data = { title: 'Trip photos', text: 'From the weekend', files: photoFiles };
const ok = supportedMembers(data);
if (ok.includes('files')) {
await navigator.share(data);
} else {
await navigator.share({ title: data.title, text: data.text, url: galleryUrl });
}

The url branch gives the recipient a link to the same photos when the device cannot carry the files themselves.

Specifications

SpecificationStatus
Web Share APIW3C
Web Share API: share() methodW3C
Web Share API: canShare() methodW3C
  • Legend
  • Yes
  • Partial
  • Flag
  • No
  • Unknown
Browser / PlatformSupportVersionsConfidenceSourceNotes
Chrome (Desktop)Partial89 → 128highsource1
Chrome (Android)Yes61highsource—
Edge (Desktop)Partial81 → 93highsource2
Firefox (Desktop)Flag71highsource3
Firefox (Android)Yes79highsource—
Safari (macOS)Yes12.1highsource—
Safari (iOS)Yes12.2highsource4
Samsung InternetYes8.0highsource5
WebView (Android)No—highsource6
  1. Only supported on ChromeOS and Windows, see bug 40542648 (https://crbug.com/40542648) and bug 40729163 (https://crbug.com/40729163).
  2. Only supported on Windows.
  3. Behind the `dom.webshare.enabled` preference (set to true).
  4. Derived by browser-compat-data mirroring from Safari.
  5. Derived by browser-compat-data mirroring from Chrome Android.
  6. Implementation tracking: https://crbug.com/40540400.

Source data: /compatibility/web-share.json · Global usage: 74 % (StatCounter 2026-05)

Source: spec · MDN · Last verified 2026-10-03 · Confidence: high (computed from sources)