# Web Share API

> navigator.share() hands a URL, title, text, or files to the OS share sheet; canShare() validates first. ShareData members, every DOMException, fallbacks.

`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](https://crbug.com/40542648) and [40729163](https://crbug.com/40729163) track macOS and Linux), Firefox 71 keeps it behind the `dom.webshare.enabled` preference, and Android WebView has no implementation ([crbug.com/40540400](https://crbug.com/40540400)). Safari 12.1 on macOS and 12.2 on iOS, Chrome 61 and Firefox 79 on Android support it without caveats.

## Syntax

```js
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`.

## Parameters

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.

## Exceptions

`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](https://www.w3.org/TR/web-share/#canshare-method) (w3.org)).

:::observed
Calling `navigator.share()` from `setTimeout` or a `DOMContentLoaded` handler in Chrome rejects with `NotAllowedError: Must be handling a user gesture to perform a share request.`; when the rejection is unhandled the DevTools Console prints `Uncaught (in promise) NotAllowedError: Must be handling a user gesture to perform a share request.` A second call while the share sheet is still open rejects with `InvalidStateError: An earlier share has not yet completed.` on Windows and ChromeOS, and a call blocked by Permissions Policy with `NotAllowedError: Permission denied`. All three strings are thrown from Chromium's [`navigator_share.cc`](https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/renderer/modules/webshare/navigator_share.cc) (chromium.googlesource.com).
:::

## Examples

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

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.

```js
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

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.

```js
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

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.

```js
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.

## See also

- [Manifest share_target](/reference/manifest/share-target/), the receiving side of sharing
- [Receive shared content (share target)](/guides/share-target/)
- [Async Clipboard API](/reference/capabilities/clipboard/), the usual fallback when `navigator.share` is undefined
- [Web Share API: share() method](https://www.w3.org/TR/web-share/#share-method) (w3.org)
- [Web Share API: validate share data](https://www.w3.org/TR/web-share/#validate-share-data) (w3.org)
- [Chromium bug 40542648: Web Share on macOS](https://crbug.com/40542648) (crbug.com)
- [Chromium bug 40540400: Web Share in Android WebView](https://crbug.com/40540400) (crbug.com)