Summary
Consumers of SocialShareButton (e.g., StabilityNexus/Chainvoice) currently have to write custom lifecycle glue code around the library because the CDN script only attaches the SocialShareButton class to window and does not auto-mount, auto-cleanup, or auto-update itself. Today's consumer code must:
- Poll for
window.SocialShareButton to exist (since script/DOM load order is not guaranteed).
- Manually call
new window.SocialShareButton({ container: '#id' }) to render the button.
- Track whether it's already initialized to avoid duplicate buttons on re-render/remount.
- Manually call
.destroy() on unmount to avoid leftover/duplicate instances.
- Manually call
.updateOptions({ url, title }) on every route change, since url/title are captured once at construction time and never recomputed automatically.
This defeats the goal of the library: providing a minimal-code drop-in share button for client applications, especially SPAs using client-side routing (e.g., React Router) where native popstate does not fire on pushState.
Proposed change
Add an opt-in auto-init routine to social-share-button.js that:
- Scans the DOM for elements marked with a
data-social-share attribute (or similar convention) on script load (DOMContentLoaded or immediately if already loaded), and instantiates SocialShareButton for each, using data-url / data-title attributes (falling back to window.location.href / document.title).
- Guards against duplicate initialization per element (e.g., store the instance on the element itself).
- Listens for
popstate and hashchange to call updateOptions({ url, title }) automatically. For SPA frameworks that use history.pushState without dispatching popstate, consider patching history.pushState/replaceState or documenting a small manual "notify" API consumers can call.
- Cleans up automatically when the container is removed from the DOM (e.g., via a
MutationObserver calling .destroy()), so SPA route unmounts don't leak instances.
Rationale
Discussed in StabilityNexus/Chainvoice PR #182, where the integration currently requires ~40 lines of useEffect-based polling/init/destroy/updateOptions glue in frontend/src/components/Navbar.jsx just to use the library correctly. This is the opposite of the library's stated goal of minimal client-side integration.
Affected areas
src/social-share-button.js (constructor/auto-init logic, currently only assigns window.SocialShareButton = SocialShareButton at the bottom with no auto-init hook)
- Documentation / README (usage instructions should show the new minimal
data-social-share attribute usage, and clarify SPA route-change behavior)
Acceptance criteria
Steps to verify
- Include only the CDN
<script> and <link> tags plus <div data-social-share></div> in a test HTML page — verify the share button renders without any extra JS.
- Click the share button and confirm the shared URL/title match the current page.
- In a SPA test harness (e.g., a small React Router app), navigate between routes and confirm the share button's URL/title update automatically, with no consumer glue code.
- Mount/unmount the container element repeatedly and confirm no duplicate buttons or memory leaks (e.g., check via DOM inspection or a leak-detection script).
- Verify existing manual usage (
new SocialShareButton({ container: ... })) continues to work unchanged for backward compatibility.
References
Requested by: @kpj2006
Summary
Consumers of
SocialShareButton(e.g., StabilityNexus/Chainvoice) currently have to write custom lifecycle glue code around the library because the CDN script only attaches theSocialShareButtonclass towindowand does not auto-mount, auto-cleanup, or auto-update itself. Today's consumer code must:window.SocialShareButtonto exist (since script/DOM load order is not guaranteed).new window.SocialShareButton({ container: '#id' })to render the button..destroy()on unmount to avoid leftover/duplicate instances..updateOptions({ url, title })on every route change, sinceurl/titleare captured once at construction time and never recomputed automatically.This defeats the goal of the library: providing a minimal-code drop-in share button for client applications, especially SPAs using client-side routing (e.g., React Router) where native
popstatedoes not fire onpushState.Proposed change
Add an opt-in auto-init routine to
social-share-button.jsthat:data-social-shareattribute (or similar convention) on script load (DOMContentLoadedor immediately if already loaded), and instantiatesSocialShareButtonfor each, usingdata-url/data-titleattributes (falling back towindow.location.href/document.title).popstateandhashchangeto callupdateOptions({ url, title })automatically. For SPA frameworks that usehistory.pushStatewithout dispatchingpopstate, consider patchinghistory.pushState/replaceStateor documenting a small manual "notify" API consumers can call.MutationObservercalling.destroy()), so SPA route unmounts don't leak instances.Rationale
Discussed in StabilityNexus/Chainvoice PR #182, where the integration currently requires ~40 lines of
useEffect-based polling/init/destroy/updateOptions glue infrontend/src/components/Navbar.jsxjust to use the library correctly. This is the opposite of the library's stated goal of minimal client-side integration.Affected areas
src/social-share-button.js(constructor/auto-init logic, currently only assignswindow.SocialShareButton = SocialShareButtonat the bottom with no auto-init hook)data-social-shareattribute usage, and clarify SPA route-change behavior)Acceptance criteria
<div data-social-share></div>to any page/component with only the CDN<script>/<link>tags, no additional JS required, and the button renders correctly.popstate/hashchange, or a documented lightweight hook forpushState-based routers).Steps to verify
<script>and<link>tags plus<div data-social-share></div>in a test HTML page — verify the share button renders without any extra JS.new SocialShareButton({ container: ... })) continues to work unchanged for backward compatibility.References
Requested by: @kpj2006