image

Snippet: Native Sharing in Salesforce with LWC and the Web Share API, One-Tap Record Sharing on Mobile

A minimal LWC that opens the device’s native share sheet (WhatsApp, Mail, Teams, etc.) so users can share a Salesforce record link in one tap — no Apex, no custom service integrations.

Salesforce is a hub of critical business information. Often, users need to share this information — a promising lead, a key account, or a public knowledge article — with colleagues. The default workflow of copy-pasting URLs is inefficient, especially on mobile devices. We can leverage the Web Share API, a standard browser feature, to provide a native sharing experience directly from a record page. This post demonstrates how to create a “Record Sharer” component that uses navigator.share() to invoke the device’s own sharing functionality.

Solution Approach

The business problem is to allow a user to share a Salesforce record using their preferred communication tool (like Teams, Slack, WhatsApp, or email) with a single click.

This Solution delegates the entire sharing UI and logic to the client’s operating system. The LWC’s role is simply to gather the necessary information — the record’s title and URL — and hand it off to the browser. The LWC’s JavaScript controller calls navigator.share(), passing an object with title, text, and url. The browser then intercepts this call and opens the device’s native share sheet, populated with the user’s own apps.

Implementation Steps

LWC — Source Code

force-app/main/default/lwc/recordSharer/recordSharer.html

<template>
<lightning-card title="Share Record" icon-name="standard:share">
<div class="slds-p-around_medium">
<template if:true={isShareAvailable}>
<lightning-button
label="Share this Record"
variant="brand"
icon-name="utility:share"
onclick={handleShareClick}>
</lightning-button>
</template>

<template if:false={isShareAvailable}>
<p>Web Share is not available in this browser. To share, please copy the URL from the address bar.</p>
</template>
</div>
</lightning-card>
</template>

force-app/main/default/lwc/recordSharer/recordSharer.js

import { LightningElement, api, wire } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';

// Example: Opportunity; change to your object as needed (e.g., Account.Name)
import NAME_FIELD from '@salesforce/schema/Opportunity.Name';

export default class RecordSharer extends NavigationMixin(LightningElement) {
@api recordId;
@api objectApiName;
@wire(getRecord, { recordId: '$recordId', fields: [NAME_FIELD] })
record;

get recordName() {
return getFieldValue(this.record?.data, NAME_FIELD) || this.recordId;
}

get isShareAvailable() {
return typeof navigator !== 'undefined' && !!navigator.share;
}

async handleShareClick() {
this[NavigationMixin.GenerateUrl]({
type: 'standard__recordPage',
attributes: { recordId: this.recordId, actionName: 'view' }
}).then((url) => this.invokeShare(url));
}

async invokeShare(recordUrl) {
try {
await navigator.share({
title: `Salesforce Record: ${this.recordName}`,
text: `Check out this record: ${this.recordName}`,
url: recordUrl
});
this.showToast('Success', 'Share dialog opened successfully.', 'success');
} catch (error) {
if (error?.name !== 'AbortError') {
this.showToast('Error', `Could not share: ${error.message}`, 'error');
}
}
}

showToast(title, message, variant) {
this.dispatchEvent(new ShowToastEvent({ title, message, variant }));
}
}

force-app/main/default/lwc/recordSharer/recordSharer.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
</targets>
</LightningComponentBundle>

(Optional) force-app/main/default/lwc/recordSharer/recordSharer.css

:host { display: block; }

Deploy & Open the Org

# (optional) create a clean project
sf project generate --name native-share --template standard
cd native-share

# login (sandbox example)
sf org login web --alias mySandbox --instance-url https://test.salesforce.com
# add the files above under force-app/
sf project deploy start --target-org mySandbox --source-dir force-app
# open the org
sf org open --target-org mySandbox

Create the Lightning Record Page

Open Lightning App Builder
 Setup → App BuilderNewRecord Page.

Choose Object & Template

  • Label: Opportunity Record with Share (or your label)
  • Object: Opportunity (or your target object)
  • Pick a template (e.g., Header + Right Sidebar).

Add the standard Record Detail

  • In the Standard components list, drag Record Detail into the main content region.
  • (Optional but common) Drag Highlights Panel into the header region for actions/key fields.
  • If you use Dynamic Forms (custom objects or supported core objects), you can instead add Field Section + Fields; both approaches are fine.

Add the share component

  • In Custom components, drag RecordSharer into a side region (e.g., Right Sidebar) or under the details section — wherever it best fits.

Save & Activate

  • Click Save, then Activate.
  • Set as Org Default (or assign to specific Apps/Profiles/Record Types).

Test

  • Open any record for that object.
  • Click Share this Record.
  • On supported browsers/devices, the native share sheet opens; otherwise, you’ll see the fallback message.

Object swap (if not Opportunity)

Change the field import in recordSharer.js and redeploy:

  • Account → @salesforce/schema/Account.Name
  • Case → @salesforce/schema/Case.CaseNumber
sf project deploy start --target-org mySandbox --source-dir force-app

Quick tips

  • User gesture + HTTPS are required for navigator.share()—the button click covers this.
  • Mobile-first: iOS Safari and Android Chrome are the most reliable; desktop support varies.
  • If the button doesn’t render, your browser likely doesn’t support Web Share — use the fallback.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top