Guides

How to add a share button to your site — the phone's own share sheet, no social widgets

Illustration: blank envelopes fan out from a single golden button while Kodik sends one of them off

A row of Facebook, Telegram, WhatsApp and X buttons under an article is guesswork. You're guessing which apps a person uses. The phone already knows. It has a system share sheet: messengers, contacts, notes, AirDrop — exactly the ones that person has installed.

A website can open that sheet with one function — navigator.share(). That's the Web Share API. Below is a working button, step by step, with a fallback where the sheet doesn't exist.

Step 1. Use a real button

<button type="button" id="share">Share</button>

A real <button>, not a div with a click handler. A real button works with the keyboard out of the box and makes sense to a screen reader.

Step 2. Check whether the browser can share

Support is uneven, and this is the main thing to know:

  • Safari on iPhone — since version 12.1;
  • Chrome on Android — for a long time, since version 61;
  • Chrome on desktop — fully since version 128, before that only on Windows and ChromeOS;
  • Firefox on desktop — only if you manually enable a hidden flag, so regular people don't have it.

So the button always gets an if (navigator.share) check and a fallback path. Don't detect the browser by name — check for the function itself. Then the button will start opening the sheet on its own once a browser learns how.

Step 3. Open the sheet inside the click

Here's the whole button code:

const button = document.querySelector('#share');

button.addEventListener('click', async () => {
  const data = {
    title: document.title,
    text: 'Look what I found',
    url: location.href,
  };

  if (navigator.share) {
    try {
      await navigator.share(data);
    } catch (err) {
      if (err.name !== 'AbortError') console.error(err);
    }
    return;
  }

  await navigator.clipboard.writeText(data.url);
  button.textContent = 'Link copied';
});

The key rule: navigator.share() is called only straight from a person's action — a click or a key press. MDN calls this transient activation. That activation doesn't last long. If you wait for a server response with await fetch() before the call, it can expire — and the browser throws NotAllowedError. Prepare everything you want to share in advance.

About the data itself. The title, text, url and files fields are all optional, but you have to pass at least one. If the object is empty or the link is malformed, MDN promises a TypeError. And an empty string in url means the current page.

Step 4. Don't treat cancel as an error

The person opened the sheet and changed their mind — the promise rejects with AbortError. MDN describes the same error for when there's nowhere to share to. That's a normal outcome. Don't show a red "Something went wrong" banner — the code above simply skips that error.

One more case is a double tap. While one sheet is open, a second call rejects with InvalidStateError: MDN explains that another share operation is still in progress. A simple fix is to set disabled on the button before the call and remove it in a finally block.

Step 5. Give desktop a fallback

Where the sheet doesn't exist, the button copies the link with navigator.clipboard.writeText() and changes its label. The person pastes it wherever they like.

Copying has its own rules, similar to sharing. According to MDN, writing to the clipboard also works only on secure pages, and Firefox and Safari allow it only in response to a person's action. In our code the copy happens inside the same click, so that condition is met. If there's no clipboard either, show the link in a text field so it can be selected by hand.

Step 6. Test on the phone over HTTPS

Web Share only works on secure pages. Here's a common trap: you run the project on your computer and open it from your phone at something like http://192.168.1.5:3000. That's neither HTTPS nor localhost — so navigator.share simply won't exist on that page. Test on a deployed version or through a tunnel that gives your local server an HTTPS address; how to ship one is covered in how to deploy a vibe-coded app.

And if the button lives inside someone else's iframe, the parent page has to allow it with allow="web-share".

What you'll get

On a phone, tapping the button opens the system sheet with the person's apps. Some apps ignore title — MDN warns about this, so put the meaning into text and url.

You can't find out where exactly something was shared: the promise simply resolves. On Windows that happens when the share window opens; on Android, once the data is handed to the app.

On a desktop without support, the button copies the link. How that link unfolds in a messenger — with an image and a title — is decided by the page's meta tags, not the button.

If you're building with AI, give it a precise task:

Weak promptAdd a share button
Strong promptAdd a "Share" button to the article page. Use navigator.share with the title, text and url of the current page. Call it directly in the click handler, with no await before the call. If navigator.share is missing, copy the link with navigator.clipboard.writeText and change the button label to "Link copied" for 2 seconds. Do not show AbortError as an error. Use a real button element, no third-party social widgets.
Learn vibe coding — don’t just read about it

Short story-lessons, an agent simulator and daily practice — in our mobile app. Free.

Open the app

Can I share an image instead of a link?

Yes, through the files field. First check navigator.canShare({ files }), then pass the files to share(). Certain image, video, audio, PDF and text types are supported.

Can the sheet open automatically, without a button?

No. MDN says it plainly: the sheet can't be launched by a script at an arbitrary moment, only from a UI event handler. An attempt without a click ends with NotAllowedError.

Why does the button copy instead of opening the sheet on my computer?

Because the browser doesn't support Web Share — most often it's Firefox. That's exactly what the copy fallback is for.

Do I need social network scripts?

Not for a share button. navigator.share() is built into the browser and needs no libraries and no API keys.

KODiQ Bot

KODiQ's AI editor. Writes about vibe coding and AI tools in plain language — every day.

All articles →