---
title: "One line of JavaScript for a real share sheet"
description: "The Web Share API hands a title, text, and URL to the operating system and opens the same native share sheet every app uses. Here's a share button that uses it, with a graceful fallback for desktop."
date: "2026-05-29"
tags: ["javascript", "web-api", "share", "frontend"]
---

Most "share" buttons on the web are a row of brand icons that each open a popup
to some intent URL. Fine, but it's a lot of markup for something the operating
system already does better. [Bilal Hussain](https://x.com/BilliCodes/status/1839186588690968994)
reminded me how little it takes to do it properly with the Web Share API.

## The one line

`navigator.share` takes a title, some text, and a URL, and hands them to the OS.
The OS opens its real share sheet, the same one your native apps use, and the
user picks Messages, AirDrop, WhatsApp, whatever:

```ts
await navigator.share({
  title: "A great article",
  text: "You should read this",
  url: "https://example.com/post",
});
```

It returns a promise that resolves when the share completes and rejects if the
user backs out, so wrap it in a `try/catch` and don't treat a cancel as an
error. On a phone it looks like this:

  src="/videos/web-share.mp4"
  className="mx-auto my-6 w-full max-w-xs rounded-xl border border-[hsl(var(--border))]"
  autoPlay
  muted
  loop
  playsInline
/>

## The catch, and the fallback

Web Share is everywhere on mobile, in Safari, and in Chrome, but not in every
desktop browser. So feature-detect it and only call it when it's there:

```ts
if (navigator.share) {
  try { await navigator.share(data); return; } catch {}
}
// otherwise: open a copy-link + social menu
```

When it's missing, fall back to the old approach: a small menu with copy-link
and the usual intent URLs (X, LinkedIn, Facebook, WhatsApp, email). Same button,
works everywhere, and on the platforms that matter most it's a single native
call.

One more thing worth knowing: `navigator.share` only runs from a user gesture
(a real click) and on a secure origin (HTTPS), so you can't fire it on load.
There's also `navigator.canShare(...)` if you want to check whether specific
data, including files, is shareable before showing the button.

Inspired by [Bilal Hussain](https://x.com/BilliCodes/status/1839186588690968994).
Grab the component on the [Share Button](/components/share-button) page.
