The ability to share content on the web is a fundamental aspect of the modern online experience. Whether it’s sharing an interesting article, a captivating image, or a noteworthy piece of information, the ability to easily share content is important.
The Web Share API is a JavaScript API that enables web developers to implement native sharing capabilities in web applications. It allows users to share text, URLs, and files directly from a webpage to user-selected sharing targets, which typically include the clipboard, email, contact, messaging applications, or Bluetooth channels.
The navigator.share method emerges as a valuable tool from the Web Share API that web developers can use to streamline content sharing in their applications. In this article, we will introduce the navigator.share method, explore advanced features that can be implemented using the API, and look at possible fallback mechanisms for unsupported browsers.
This article assumes that you have an intermediate level of knowledge in working with JavaScript.
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
The Web Share API is a JavaScript API that is comprised of a navigator object with two essential methods:
navigator.canShare()navigator.share()navigator.canShare methodThe navigator.canShare method checks if the data to be shared is shareable before passing it to the navigator.share method. It ensures that only shareable data is shared, and that the user is not presented with an error message if the data cannot be shared.
This method takes an object as an argument and returns true if the object contains valid and shareable data:
const data = {
title: 'Item 1',
text: 'This is the first item',
url: 'https://example.com/item1',
};
navigator.canShare(data);
If the data cannot be validated, the method returns false. This can occur for one or more of the following reasons:
navigator.share methodThe navigator.share method invokes the native sharing mechanism of the user’s operating system to share specified data to available targets like social media, messaging apps, or other installed applications on the user’s device.
The method takes an object containing the data to be shared using the following property values:
title (string): The title of the content you want to sharetext (string): The text or description of the contenturl (string): The URL of the content you want to sharefiles (array): The file or files you want to shareconst data = {
title: '...',
text: '...',
url: '...',
file: [...]
};
The highlighted properties are optional, but at least one of them must be specified.
Additionally, only the share data properties that are understood by the user agent (browser) are assessed. Properties that are unknown to the user agent are ignored. So if your user agent doesn’t recognize the file property as shareable data and it is declared in your data object, the file property will be ignored.
Once the data parameter is passed to the navigator.share method and is triggered by the user, using a button or any form of transient activation (more on this later), the method returns a promise that resolves when content has been successfully shared or rejects if the sharing process fails:
navigator.share(data)
...
.then(() => {
console.log('Sharing was successful');
})
.catch((error) => {
console.error('Sharing failed:', error);
});
In this example, the method logs the message "Sharing was successful" if the data has been successfully shared to a target. If the sharing process fails, the method logs the message "Sharing failed", followed by the error message.
We mentioned transient activation in the previous paragraph. This is a window state that indicates a user’s recent interaction, such as pressing a button, moving a mouse, or using a menu. This state is sometimes used as a mechanism to ensure that certain web APIs can only function through user interaction.
This means that APIs requiring transient operations cannot be initiated by a script; they can only be triggered through a UI element’s event handler and by user interaction.
The Web Share API is gated by the transient activation mechanism. If you attempt to trigger the navigator.share function with a script, you will encounter an exception, specifically the notAllowed error. This mechanism is put in place to protect end users from malicious actors who may attempt to share harmful content on the user’s device without their knowledge.
Before delving into the specifics, let’s address the issue of browser support. The Web Share API has seen less adoption since its introduction in Chrome 61 for Android six years ago.
Considering the significant number of experimental features that have achieved cross-browser compatibility this year alone, it is surprising that the Web Share API has not made much progress. While it has gained some traction over the years, at the time of writing, it is still not widely supported.
Browsers such as Safari and Edge already have complete compatibility with the feature, while Chrome has partial support. Firefox and Opera, on the other hand, do not appear to have any plans for the feature at this time.
It should go without saying that before using the Web Share API in your projects, it is important to check the client’s browser compatibility. If the browser is not compatible, you should provide a fallback or inform the user that sharing is not available on their device. This will ensure that your site works properly and prevent user experience issues in your application.
Fortunately, creating a fallback for the Web Share API in your applications is also a straightforward process. It involves providing an alternative sharing mechanism to the Web Share API. One common approach is to use the classic sharing links or buttons with the target="blank" attribute, which allows users to manually share content if their browser is not compatible.
In the markup example below, two buttons with links are provided below the Web Share API button. These buttons serve as a fallback mechanism in the event that the navigator.share method is not present in the navigator object:
<main>
<h1>Amazing Content</h1>
<section>
<p>
...
</p>
</section>
<h3>Share this content</h3>
<p>Click the button to share this content:</p>
<!-- Web Share API Button (Hidden by Default) -->
<button id="shareButton" style="display: none">
Share using Web Share API <i class="fa-solid fa-share"></i>
</button>
<!-- Fallback Sharing Links -->
<div id="links" style="display: none">
<a
href="https://www.facebook.com/sharer/sharer.php?u=https://example.com"
target="_blank"
rel="noopener noreferrer"
>
<button><i class="fa-brands fa-facebook"></i> Facebook</button></a
>
<a
href="https://twitter.com/intent/tweet?text=Check%20out%20this%20awesome%20content&url=https://example.com"
target="_blank"
rel="noopener noreferrer"
>
<button><i class="fa-brands fa-twitter"> </i> Twitter</button></a
>
</div>
</main>
Note that both elements are hidden by default. This is done so that either of the elements can be displayed based on the availability of the navigator.share method on the client’s browser using JavaScript:
if (navigator.share) {
// Enable the Web Share API button
const shareButton = document.getElementById('shareButton');
shareButton.addEventListener('click', () => {
navigator.share({
title: 'Awesome Content',
text: 'Check out this awesome content!',
url: 'https://example.com',
})
.then(() => console.log('Shared successfully'))
.catch((error) => console.error('Sharing failed:', error));
});
} else {
// If Web Share API is not supported, hide the button
const shareButton = document.getElementById('shareButton');
shareButton.style.display = 'none';
}
In this case, the share button will only be displayed if the navigator.share method is present in the client’s browser. If the method is not present, the sharing links will be displayed instead:

As you can see in the GIF above, the share button is hidden, and the sharing links remain visible in a Firefox browser. However, in Edge, which has full compatibility with the Web Share API, the button is visible.
Alternatively, we can create a fallback using the pop-up window method, which allows users to share content from a pop-up window without leaving the page. This method involves using the window.open() method and the customShareWindow parameter:
function popUpShare() {
const sharingURL = 'https://example.com/share';
// Open a new pop-up window with the sharing URL.
window.open(sharingURL, 'CustomShareWindow', 'width=600, height=400');
}
const shareButton = document.getElementById("shareButton");
shareButton.addEventListener('click', popUpShare);
The window.open() method takes two or three parameters, which include the sharing URL, target, and a comma-separated list of window features that includes the window’s default size, position, and more.
In this example, we set the width and height of the pop-up window to 600 and 400 respectively, and set target to CustomShareWindow. You can learn more about the window.open() API on the MDN web docs.
Here’s how our example code will look with the window pop-up fallback implemented:
if (navigator.share) {
const title = document.title;
const header = document.querySelector("header").innerText;
// If Web Share API is supported, enable the Web Share API button
const shareButton = document.getElementById("shareButton");
shareButton.style.display = "block"; // Show the button
shareButton.addEventListener("click", () => {
navigator
.share({
title,
text: header,
url: window.location.href,
})
.then(() => console.log("Shared successfully"))
.catch((error) => console.error("Sharing failed:", error));
});
} else {
// Enable the sharing links button
const linkContainer = document.getElementById("links");
linkContainer.style.display = "block";
}
function popUpShare(sharingURL) {
// Open a new pop-up window with the sharing URL.
window.open(sharingURL, 'CustomShareWindow', 'width=500, height=400, left=400, top=100');
}
const facebook = document.getElementById("facebook");
const twitter = document.getElementById("twitter");
facebook.addEventListener("click", ()=> popUpShare(
"https://www.facebook.com/sharer/sharer.php?u=https://example.com"
));
twitter.addEventListener("click", ()=> popUpShare(
"https://twitter.com/intent/tweet?text=Check%20out%20this%20awesome%20content&url=https://example.com"
));

Though this method cannot rival the capabilities of the navigator.share method, it does provide a comparable experience that can enhance your application’s user experience and user retention.
As users interact with your applications, a great deal of information is subject to change, such as data updates, page title and content, and other variables. Sharing outdated content would not be beneficial to your application’s user experience.
Therefore, in most cases, it is necessary to share dynamic content. Sharing dynamic content entails generating a shareable URL that captures the dynamic content’s current state.
Let’s assume that we have a blog site where we want to implement a share button that shares the content of the current page when the navigator.share method is invoked. It would be counterproductive to create a sharing function and hardcode the URL and header content for each blog post. Instead, we can create just one sharing function with the navigator.share method and dynamically pass the title and header of each page the users visit to it.
Here is an example of how we can implement this:
function share() {
const title = document.title;
const header = document.querySelector('header').innerText;
navigator.share({
title,
text: header,
url: window.location.href
});
}
In this instance, we used the document and window objects to obtain the title, header, and link of the actively focused tab or window on the user’s browser, and then passed them to the navigator.share method. This ensures that the API will always share the intended content when the user clicks on the share button.
Here’s how our previous example will look with the dynamic content-sharing feature implemented above:

This dynamic-sharing approach isn’t limited to the example above — you can employ the same technique to share a variety of dynamic content.
Due to security reasons, the navigator.share method doesn’t allow us to specify the target of the shared content or how it appears in the sharing dialog mechanism of the client’s underlying operating system. This is determined by the browser.
However, if you have a progressive web application (PWA) and you want the sharing mechanism of the user’s OS to consider it a possible sharing option, you must meet some criteria set by Chrome.
These criteria are as follows:
Most of the criteria are optional, with the exception of the first one on the list: register as a share target. This is a foundational step in making your PWA a sharing option for the navigator.share method. It entails registering the PWA as a share target in the web manifest file (manifest.json) by including the share_target field.
The share field specifies the action that should be taken when the user shares content with the app. The data types and formats that the PWA can accept can also be defined:
{
"name": "My PWA",
"start_url": "/index.html",
"display": "standalone",
"share_target": {
"action": "/share-target",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"title": "text",
"text": "text",
"url": "url"
}
}
}
The params object specifies the kind of shared content the PWA can accept. In this case, the app will only accept shared contents with a title, text, and URL.
A share target handler can be a script or service worker that listens for incoming shared data. When content is shared with your app, the handler processes the shared data and performs the necessary actions. Here’s a simplified example of a target handler:
// Service worker or JavaScript code in your PWA
self.addEventListener('sharetarget', (event) => {
// Extract shared data
const title = event.data.title;
const text = event.data.text;
const url = event.data.url;
// Process the shared data
// You can perform actions like displaying the shared content or saving it.
console.log(`Shared content: Title - ${title}, Text - ${text}, URL - ${url}`);
});
The navigator.share method doesn’t have a built-in feature that allows us to perform batch sharing by default. Therefore, if you need to share multiple items at once, the method in its original form will not be very helpful.
However, there are methods to implement such a feature. One approach is to store the provided data in an array, iterate through it, and sequentially pass each item in the array to the navigator.share method:
const data = [
{
title: 'Item 1',
text: 'This is the first item',
url: 'https://example.com/item1',
},
{
title: 'Item 2',
text: 'This is the second item',
url: 'https://example.com/item2',
},
];
// Function to share items sequentially
async function shareItems() {
for (const item of data) {
try {
await navigator.share(item);
console.log(`Shared successfully: ${item.title}`);
} catch (error) {
console.error(`Sharing failed: ${item.title}`, error);
}
}
}
shareButton.addEventListener('click', shareItems);
Although this approach might appear valid, it won’t perform as intended. As mentioned in the previous section, the navigator.share method requires transient activation to operate.
Consequently, it’s not possible to share multiple items collectively. While the initial button click will successfully share the first item in the array, the subsequent items will trigger errors because they would be invoked without user interaction:

The initial item in the array is successfully shared, but the subsequent item encounters sharing failure. This is because the navigator.share method cannot be triggered by a script alone.
A potential solution would involve creating buttons that appear sequentially with every loop iteration. Upon clicking these buttons, the navigator.share method could be invoked for each item in the array:
const shareButton = document.getElementById("shareButton");
const shareContainer = document.getElementById('shareContainer');
const data = [
{
title: 'Item 1',
text: 'This is the first item',
url: 'https://example.com/item1',
},
{
title: 'Item 2',
text: 'This is the second item',
url: 'https://example.com/item2',
},
];
function shareSequentially(index) {
if (index < shareData.length) {
const item = data[index];
const button = document.createElement('button');
button.textContent = `Share ${item.title}`;
button.addEventListener('click', () => shareItem(item, button, index));
shareContainer.appendChild(button);
} else {
console.log('All items shared');
}
}
function shareItem(item, button, index) {
try {
navigator.share(item).then(() => {
console.log(`Shared successfully: ${item.title}`);
});
} catch (error) {
console.error(`Sharing failed: ${item.title}`, error);
} finally {
button.parentNode.removeChild(button);
shareSequentially(index + 1);
}
}
// Attach a click event listener to the share button to create share buttons
shareButton.addEventListener('click', () => shareSequentially(0));
In the code above, we create a shareSequentially function that takes an index parameter to track the current item being shared. Inside the function, a share button is created for the current item. The click event handler for each button is set to call the shareItem function, passing the current item, the button, and the index.
The shareItem function invokes the navigator.share method with the current item. After sharing the item (whether successfully or not), it removes the button from the DOM and proceeds to share the next item in the array, after the shareSequentially function has created and rendered a new button.
The corresponding markup code will be as follows:
<p>Click the button to share items:</p>
<button id="shareButton">
Share Items
</button>
<div id="shareContainer">
<!-- Share buttons will be added here -->
</div>

This approach is a bit hacky, but it gets the job done and is the closest we’ll get to batch sharing with the navigator.share method.
In as much as we’d like it to be, the navigator.share method is not a universally applicable solution for web content sharing and is unlikely to become one anytime soon due to the security risks associated with the API.
However, given the myriad of fallbacks that can be implemented for the API, adopting it should not be an issue. Additionally, the support that the API does provide can greatly improve the user experience in your applications.
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!

Vibe coding isn’t just AI-assisted chaos. Here’s how to avoid insecure, unreadable code and turn your “vibes” into real developer productivity.

GitHub SpecKit brings structure to AI-assisted coding with a spec-driven workflow. Learn how to build a consistent, React-based project guided by clear specs and plans.

:has(), with examplesThe CSS :has() pseudo-class is a powerful new feature that lets you style parents, siblings, and more – writing cleaner, more dynamic CSS with less JavaScript.

Kombai AI converts Figma designs into clean, responsive frontend code. It helps developers build production-ready UIs faster while keeping design accuracy and code quality intact.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now
One Reply to "An advanced guide to the Web Share API and navigator.share()"
Amazing article! Can you share the demo and source code 🙂
Because my browser is supporting the API but not working due to permissions.