I’ll build this as a safe, standalone advanced share module for RX Theme: native Web Share, copy link, social share URLs, floating bar, shortcode/button support, analytics hooks, accessibility, and no jQuery dependency.
Friend, create this file:
assets/static-js/static-chunks-js/chunk-014-share.js
Paste this full advanced code:
/**
* RX Theme - Advanced Share Chunk
* File: assets/static-js/static-chunks-js/chunk-014-share.js
*
* Features:
* - Native Web Share API support
* - Copy current page link
* - Facebook, X/Twitter, LinkedIn, WhatsApp, Telegram, Email share
* - Floating share bar
* - Inline share buttons
* - Reading-position aware floating bar
* - Accessible aria-label support
* - Keyboard friendly
* - Auto button creation
* - Data attribute customization
* - Lightweight analytics event hooks
* - No jQuery dependency
*/
(function () {
'use strict';
const RXShare = {
config: {
selectors: {
inlineContainer: '[data-rx-share]',
floatingContainer: '[data-rx-floating-share]',
shareButton: '[data-rx-share-button]',
copyButton: '[data-rx-copy-link]',
nativeButton: '[data-rx-native-share]',
article: 'article, .entry-content, .rx-post-content, main',
},
networks: {
facebook: {
label: 'Facebook',
icon: 'f',
url: 'https://www.facebook.com/sharer/sharer.php?u={url}',
},
x: {
label: 'X',
icon: '𝕏',
url: 'https://twitter.com/intent/tweet?url={url}&text={title}',
},
linkedin: {
label: 'LinkedIn',
icon: 'in',
url: 'https://www.linkedin.com/sharing/share-offsite/?url={url}',
},
whatsapp: {
label: 'WhatsApp',
icon: 'wa',
url: 'https://api.whatsapp.com/send?text={title}%20{url}',
},
telegram: {
label: 'Telegram',
icon: 'tg',
url: 'https://t.me/share/url?url={url}&text={title}',
},
email: {
label: 'Email',
icon: '@',
url: 'mailto:?subject={title}&body={title}%0A%0A{url}',
},
},
defaultNetworks: ['facebook', 'x', 'linkedin', 'whatsapp', 'telegram', 'email'],
popup: {
width: 680,
height: 520,
},
floating: {
enabled: true,
showAfterScroll: 250,
hideNearFooter: true,
},
copy: {
successText: 'Link copied!',
errorText: 'Copy failed',
resetDelay: 1800,
},
classes: {
wrapper: 'rx-share',
list: 'rx-share__list',
item: 'rx-share__item',
button: 'rx-share__button',
nativeButton: 'rx-share__button--native',
copyButton: 'rx-share__button--copy',
floating: 'rx-share--floating',
visible: 'is-visible',
copied: 'is-copied',
hidden: 'is-hidden',
},
},
state: {
initialized: false,
pageData: null,
floatingElement: null,
},
init() {
if (this.state.initialized) return;
this.state.pageData = this.getPageData();
this.injectBaseStyles();
this.renderInlineContainers();
this.renderFloatingShare();
this.bindExistingButtons();
this.bindGlobalEvents();
this.state.initialized = true;
this.dispatchEvent('rxShareReady', {
page: this.state.pageData,
});
},
getPageData(sourceElement) {
const canonical = document.querySelector('link[rel="canonical"]');
const ogTitle = document.querySelector('meta[property="og:title"]');
const ogDescription = document.querySelector('meta[property="og:description"]');
const metaDescription = document.querySelector('meta[name="description"]');
const url =
sourceElement?.dataset?.rxShareUrl ||
canonical?.href ||
window.location.href;
const title =
sourceElement?.dataset?.rxShareTitle ||
ogTitle?.content ||
document.title ||
'';
const description =
sourceElement?.dataset?.rxShareDescription ||
ogDescription?.content ||
metaDescription?.content ||
'';
return {
url: this.cleanUrl(url),
title: this.cleanText(title),
description: this.cleanText(description),
};
},
cleanUrl(url) {
try {
const parsed = new URL(url, window.location.origin);
parsed.hash = '';
return parsed.toString();
} catch (error) {
return window.location.href.split('#')[0];
}
},
cleanText(text) {
return String(text || '')
.replace(/\s+/g, ' ')
.trim();
},
encode(value) {
return encodeURIComponent(value || '');
},
buildShareUrl(networkKey, pageData) {
const network = this.config.networks[networkKey];
if (!network) return '';
return network.url
.replaceAll('{url}', this.encode(pageData.url))
.replaceAll('{title}', this.encode(pageData.title))
.replaceAll('{description}', this.encode(pageData.description));
},
getNetworksFromElement(element) {
const raw = element?.dataset?.rxShareNetworks;
if (!raw) {
return this.config.defaultNetworks;
}
return raw
.split(',')
.map((item) => item.trim())
.filter((item) => this.config.networks[item]);
},
renderInlineContainers() {
const containers = document.querySelectorAll(this.config.selectors.inlineContainer);
containers.forEach((container) => {
if (container.dataset.rxShareRendered === 'true') return;
const pageData = this.getPageData(container);
const networks = this.getNetworksFromElement(container);
const showNative = container.dataset.rxShareNative !== 'false';
const showCopy = container.dataset.rxShareCopy !== 'false';
const shareElement = this.createShareElement({
pageData,
networks,
showNative,
showCopy,
floating: false,
});
container.appendChild(shareElement);
container.dataset.rxShareRendered = 'true';
});
},
renderFloatingShare() {
if (!this.config.floating.enabled) return;
const existing = document.querySelector(this.config.selectors.floatingContainer);
if (existing) {
if (existing.dataset.rxFloatingRendered === 'true') return;
const networks = this.getNetworksFromElement(existing);
const pageData = this.getPageData(existing);
const shareElement = this.createShareElement({
pageData,
networks,
showNative: existing.dataset.rxShareNative !== 'false',
showCopy: existing.dataset.rxShareCopy !== 'false',
floating: true,
});
existing.appendChild(shareElement);
existing.dataset.rxFloatingRendered = 'true';
this.state.floatingElement = existing;
this.updateFloatingVisibility();
return;
}
const article = document.querySelector(this.config.selectors.article);
if (!article || document.body.dataset.rxFloatingShare === 'false') {
return;
}
const floatingContainer = document.createElement('div');
floatingContainer.setAttribute('data-rx-floating-share', 'true');
floatingContainer.className = 'rx-floating-share-container';
const shareElement = this.createShareElement({
pageData: this.state.pageData,
networks: this.config.defaultNetworks,
showNative: true,
showCopy: true,
floating: true,
});
floatingContainer.appendChild(shareElement);
document.body.appendChild(floatingContainer);
this.state.floatingElement = floatingContainer;
this.updateFloatingVisibility();
},
createShareElement(options) {
const {
pageData,
networks,
showNative,
showCopy,
floating,
} = options;
const wrapper = document.createElement('div');
wrapper.className = [
this.config.classes.wrapper,
floating ? this.config.classes.floating : '',
]
.filter(Boolean)
.join(' ');
wrapper.setAttribute('role', 'navigation');
wrapper.setAttribute('aria-label', 'Share this page');
const list = document.createElement('div');
list.className = this.config.classes.list;
if (showNative && this.canUseNativeShare(pageData)) {
const nativeButton = this.createNativeShareButton(pageData);
list.appendChild(nativeButton);
}
networks.forEach((networkKey) => {
const button = this.createNetworkButton(networkKey, pageData);
if (button) list.appendChild(button);
});
if (showCopy) {
const copyButton = this.createCopyButton(pageData);
list.appendChild(copyButton);
}
wrapper.appendChild(list);
return wrapper;
},
createNetworkButton(networkKey, pageData) {
const network = this.config.networks[networkKey];
if (!network) return null;
const button = document.createElement('button');
button.type = 'button';
button.className = `${this.config.classes.button} rx-share__button--${networkKey}`;
button.dataset.rxShareButton = networkKey;
button.dataset.rxShareUrl = pageData.url;
button.dataset.rxShareTitle = pageData.title;
button.setAttribute('aria-label', `Share on ${network.label}`);
button.setAttribute('title', `Share on ${network.label}`);
button.innerHTML = `
<span class="rx-share__icon" aria-hidden="true">${network.icon}</span>
<span class="rx-share__text">${network.label}</span>
`;
button.addEventListener('click', () => {
this.shareToNetwork(networkKey, pageData);
});
return button;
},
createNativeShareButton(pageData) {
const button = document.createElement('button');
button.type = 'button';
button.className = `${this.config.classes.button} ${this.config.classes.nativeButton}`;
button.dataset.rxNativeShare = 'true';
button.setAttribute('aria-label', 'Share this page');
button.setAttribute('title', 'Share this page');
button.innerHTML = `
<span class="rx-share__icon" aria-hidden="true">↗</span>
<span class="rx-share__text">Share</span>
`;
button.addEventListener('click', () => {
this.nativeShare(pageData);
});
return button;
},
createCopyButton(pageData) {
const button = document.createElement('button');
button.type = 'button';
button.className = `${this.config.classes.button} ${this.config.classes.copyButton}`;
button.dataset.rxCopyLink = 'true';
button.dataset.rxCopyValue = pageData.url;
button.setAttribute('aria-label', 'Copy page link');
button.setAttribute('title', 'Copy page link');
button.innerHTML = `
<span class="rx-share__icon" aria-hidden="true">⛓</span>
<span class="rx-share__text">Copy</span>
`;
button.addEventListener('click', () => {
this.copyLink(pageData.url, button);
});
return button;
},
bindExistingButtons() {
const shareButtons = document.querySelectorAll(this.config.selectors.shareButton);
shareButtons.forEach((button) => {
if (button.dataset.rxShareBound === 'true') return;
button.addEventListener('click', () => {
const network = button.dataset.rxShareButton;
const pageData = this.getPageData(button);
if (network) {
this.shareToNetwork(network, pageData);
}
});
button.dataset.rxShareBound = 'true';
});
const copyButtons = document.querySelectorAll(this.config.selectors.copyButton);
copyButtons.forEach((button) => {
if (button.dataset.rxCopyBound === 'true') return;
button.addEventListener('click', () => {
const value =
button.dataset.rxCopyValue ||
button.dataset.rxShareUrl ||
this.state.pageData.url;
this.copyLink(value, button);
});
button.dataset.rxCopyBound = 'true';
});
const nativeButtons = document.querySelectorAll(this.config.selectors.nativeButton);
nativeButtons.forEach((button) => {
if (button.dataset.rxNativeBound === 'true') return;
button.addEventListener('click', () => {
const pageData = this.getPageData(button);
this.nativeShare(pageData);
});
button.dataset.rxNativeBound = 'true';
});
},
bindGlobalEvents() {
let ticking = false;
window.addEventListener(
'scroll',
() => {
if (ticking) return;
ticking = true;
window.requestAnimationFrame(() => {
this.updateFloatingVisibility();
ticking = false;
});
},
{ passive: true }
);
window.addEventListener(
'resize',
this.debounce(() => {
this.updateFloatingVisibility();
}, 150),
{ passive: true }
);
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
this.closeAllPopupsSignal();
}
});
},
canUseNativeShare(pageData) {
if (!navigator.share) return false;
try {
return navigator.canShare
? navigator.canShare({
title: pageData.title,
text: pageData.description,
url: pageData.url,
})
: true;
} catch (error) {
return true;
}
},
async nativeShare(pageData) {
if (!navigator.share) {
this.copyLink(pageData.url);
return;
}
try {
await navigator.share({
title: pageData.title,
text: pageData.description,
url: pageData.url,
});
this.track('native_share_success', {
network: 'native',
url: pageData.url,
title: pageData.title,
});
} catch (error) {
if (error && error.name === 'AbortError') {
this.track('native_share_cancelled', {
network: 'native',
url: pageData.url,
});
return;
}
this.copyLink(pageData.url);
this.track('native_share_failed', {
network: 'native',
url: pageData.url,
error: error?.message || 'Unknown error',
});
}
},
shareToNetwork(networkKey, pageData) {
const shareUrl = this.buildShareUrl(networkKey, pageData);
if (!shareUrl) return;
if (networkKey === 'email') {
window.location.href = shareUrl;
this.track('share_click', {
network: networkKey,
url: pageData.url,
title: pageData.title,
});
return;
}
this.openPopup(shareUrl, `rx-share-${networkKey}`);
this.track('share_click', {
network: networkKey,
url: pageData.url,
title: pageData.title,
});
},
openPopup(url, name) {
const width = this.config.popup.width;
const height = this.config.popup.height;
const left = Math.max(0, window.screenX + (window.outerWidth - width) / 2);
const top = Math.max(0, window.screenY + (window.outerHeight - height) / 2);
const features = [
`width=${width}`,
`height=${height}`,
`left=${left}`,
`top=${top}`,
'menubar=no',
'toolbar=no',
'location=no',
'status=no',
'scrollbars=yes',
'resizable=yes',
].join(',');
const popup = window.open(url, name, features);
if (popup && popup.focus) {
popup.focus();
} else {
window.location.href = url;
}
},
async copyLink(value, button) {
const text = String(value || this.state.pageData.url);
let copied = false;
try {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(text);
copied = true;
} else {
copied = this.fallbackCopy(text);
}
} catch (error) {
copied = this.fallbackCopy(text);
}
if (button) {
this.updateCopyButton(button, copied);
}
this.showToast(
copied ? this.config.copy.successText : this.config.copy.errorText,
copied ? 'success' : 'error'
);
this.track(copied ? 'copy_link_success' : 'copy_link_failed', {
url: text,
});
return copied;
},
fallbackCopy(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', '');
textarea.style.position = 'fixed';
textarea.style.top = '-9999px';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
textarea.select();
textarea.setSelectionRange(0, textarea.value.length);
let success = false;
try {
success = document.execCommand('copy');
} catch (error) {
success = false;
}
document.body.removeChild(textarea);
return success;
},
updateCopyButton(button, copied) {
const textElement = button.querySelector('.rx-share__text');
const originalText = button.dataset.rxOriginalText || textElement?.textContent || 'Copy';
button.dataset.rxOriginalText = originalText;
if (copied) {
button.classList.add(this.config.classes.copied);
if (textElement) textElement.textContent = 'Copied';
} else {
if (textElement) textElement.textContent = 'Failed';
}
window.setTimeout(() => {
button.classList.remove(this.config.classes.copied);
if (textElement) textElement.textContent = originalText;
}, this.config.copy.resetDelay);
},
showToast(message, type) {
let toast = document.querySelector('.rx-share-toast');
if (!toast) {
toast = document.createElement('div');
toast.className = 'rx-share-toast';
toast.setAttribute('role', 'status');
toast.setAttribute('aria-live', 'polite');
document.body.appendChild(toast);
}
toast.textContent = message;
toast.dataset.type = type || 'info';
toast.classList.add('is-visible');
clearTimeout(toast.rxTimer);
toast.rxTimer = window.setTimeout(() => {
toast.classList.remove('is-visible');
}, 1800);
},
updateFloatingVisibility() {
const floating = this.state.floatingElement;
if (!floating) return;
const scrollY = window.scrollY || document.documentElement.scrollTop;
const shouldShow = scrollY > this.config.floating.showAfterScroll;
let nearFooter = false;
if (this.config.floating.hideNearFooter) {
const footer = document.querySelector('footer, .site-footer, #footer');
if (footer) {
const footerRect = footer.getBoundingClientRect();
nearFooter = footerRect.top < window.innerHeight - 80;
}
}
floating.classList.toggle(this.config.classes.visible, shouldShow && !nearFooter);
floating.classList.toggle(this.config.classes.hidden, !shouldShow || nearFooter);
},
closeAllPopupsSignal() {
this.dispatchEvent('rxShareEscape', {
source: 'keyboard',
});
},
track(eventName, detail) {
const payload = {
event: eventName,
detail: detail || {},
timestamp: Date.now(),
};
this.dispatchEvent('rxShareTrack', payload);
if (window.dataLayer && Array.isArray(window.dataLayer)) {
window.dataLayer.push({
event: `rx_${eventName}`,
rx_share: detail || {},
});
}
if (typeof window.gtag === 'function') {
window.gtag('event', eventName, {
event_category: 'RX Share',
event_label: detail?.network || detail?.url || 'share',
page_location: detail?.url || window.location.href,
});
}
},
dispatchEvent(name, detail) {
document.dispatchEvent(
new CustomEvent(name, {
bubbles: true,
detail,
})
);
},
debounce(callback, delay) {
let timer;
return function debounced() {
const args = arguments;
const context = this;
clearTimeout(timer);
timer = setTimeout(() => {
callback.apply(context, args);
}, delay);
};
},
injectBaseStyles() {
if (document.getElementById('rx-share-base-style')) return;
const style = document.createElement('style');
style.id = 'rx-share-base-style';
style.textContent = `
.rx-share {
--rx-share-gap: 8px;
--rx-share-size: 42px;
--rx-share-radius: 999px;
--rx-share-bg: #ffffff;
--rx-share-text: #1f2937;
--rx-share-border: rgba(15, 23, 42, 0.12);
--rx-share-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
--rx-share-hover-bg: #f8fafc;
--rx-share-focus: #2563eb;
}
.rx-share__list {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--rx-share-gap);
}
.rx-share__button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 7px;
min-width: var(--rx-share-size);
min-height: var(--rx-share-size);
padding: 0 14px;
border: 1px solid var(--rx-share-border);
border-radius: var(--rx-share-radius);
background: var(--rx-share-bg);
color: var(--rx-share-text);
font: inherit;
font-size: 14px;
line-height: 1;
cursor: pointer;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
transition:
transform 160ms ease,
background-color 160ms ease,
border-color 160ms ease,
box-shadow 160ms ease;
}
.rx-share__button:hover {
background: var(--rx-share-hover-bg);
transform: translateY(-1px);
box-shadow: var(--rx-share-shadow);
}
.rx-share__button:focus-visible {
outline: 3px solid color-mix(in srgb, var(--rx-share-focus), transparent 70%);
outline-offset: 2px;
}
.rx-share__icon {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 18px;
font-weight: 700;
text-transform: uppercase;
}
.rx-share__text {
white-space: nowrap;
}
.rx-share--floating .rx-share__list {
flex-direction: column;
}
.rx-floating-share-container {
position: fixed;
z-index: 900;
left: 16px;
top: 50%;
transform: translate3d(-120%, -50%, 0);
opacity: 0;
pointer-events: none;
transition:
transform 220ms ease,
opacity 220ms ease;
}
.rx-floating-share-container.is-visible {
transform: translate3d(0, -50%, 0);
opacity: 1;
pointer-events: auto;
}
.rx-floating-share-container .rx-share__button {
width: var(--rx-share-size);
height: var(--rx-share-size);
padding: 0;
}
.rx-floating-share-container .rx-share__text {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
}
.rx-share-toast {
position: fixed;
z-index: 1000;
left: 50%;
bottom: 24px;
transform: translate3d(-50%, 20px, 0);
opacity: 0;
pointer-events: none;
padding: 10px 14px;
border-radius: 999px;
background: #111827;
color: #ffffff;
font-size: 14px;
line-height: 1.3;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
transition:
transform 180ms ease,
opacity 180ms ease;
}
.rx-share-toast.is-visible {
transform: translate3d(-50%, 0, 0);
opacity: 1;
}
@media (max-width: 991px) {
.rx-floating-share-container {
left: 50%;
top: auto;
bottom: 16px;
transform: translate3d(-50%, 140%, 0);
}
.rx-floating-share-container.is-visible {
transform: translate3d(-50%, 0, 0);
}
.rx-share--floating .rx-share__list {
flex-direction: row;
padding: 8px;
border: 1px solid var(--rx-share-border);
border-radius: 999px;
background: rgba(255, 255, 255, 0.94);
box-shadow: var(--rx-share-shadow);
backdrop-filter: blur(12px);
}
}
@media (max-width: 520px) {
.rx-share__button {
min-width: 38px;
min-height: 38px;
padding: 0 11px;
font-size: 13px;
}
.rx-floating-share-container .rx-share__button {
width: 38px;
height: 38px;
}
}
@media (prefers-reduced-motion: reduce) {
.rx-share__button,
.rx-floating-share-container,
.rx-share-toast {
transition: none;
}
.rx-share__button:hover {
transform: none;
}
}
`;
document.head.appendChild(style);
},
};
window.RXShare = RXShare;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => RXShare.init());
} else {
RXShare.init();
}
})();
Use it in your theme HTML like this:
<div data-rx-share></div>
Custom networks:
<div data-rx-share data-rx-share-networks="facebook,x,linkedin,whatsapp,telegram,email"></div>
Floating share bar will auto-create after scrolling. To disable floating share on a page:
<body data-rx-floating-share="false">
For WordPress enqueue, add this in your theme enqueue file:
wp_enqueue_script(
'rx-theme-share-chunk',
get_template_directory_uri() . '/assets/static-js/static-chunks-js/chunk-014-share.js',
array(),
wp_get_theme()->get('Version'),
true
);
Best loading style for this file:
wp_script_add_data('rx-theme-share-chunk', 'defer', true);
This file is safe as a static chunk because it waits for DOM ready, does not depend on jQuery, and will not break the page if no share container exists.