Share Bar
alphav0.2.0Social share button row — nine built-in platforms, custom targets, and copy-link with success feedback.
Context
Reach for it on news article footers, blog post footers, product page social rows, video player share clusters, doc page share affordances. Built-in URL templates for Twitter / Facebook / LinkedIn / Reddit / WhatsApp / Telegram / Email / Threads / Bluesky. Copy-link button uses navigator.clipboard with execCommand fallback for older / insecure-context browsers; success/error feedback is visual (icon flip) + audible (aria-live). Custom targets via 'kind: custom' with arbitrary onClick. Analytics hook via onShare(targetKind). SSR-safe — window.location.href read at click time, not render time.
Installation
pnpm dlx shadcn@latest init"registries": {
"@ilinxa": "https://ui.ilinxa.com/r/{name}.json"
}pnpm dlx shadcn@latest add @ilinxa/share-barAdd -fixtures for dummy data:
pnpm dlx shadcn@latest add @ilinxa/share-bar-fixturesPreview
Share
Click Copy link — icon flips to a check for 2s.
Demo source
Usage
When to use
A horizontal cluster of social-share buttons + a copy-link button, typically at the bottom of an article (or pinned to the side as a share rail). Each social button opens the platform's share intent in a new window with the page's URL prefilled; the copy button writes the URL to the clipboard with a 2-second visual + audible success affordance.
Basic example
import { ShareBar } from "@/components/share-bar"
export function ArticleFooter() {
return (
<ShareBar
url="https://example.com/news/sustainable-cities"
title="Sustainable cities, then and now"
headingAs="h4"
divider
targets={[
{ kind: "twitter" },
{ kind: "facebook" },
{ kind: "linkedin" },
{ kind: "copy" },
]}
/>
)
}Built-in platforms
Twitter / Facebook / LinkedIn / Reddit / WhatsApp / Telegram / Email / Threads / Bluesky — each ships with a share-intent URL template + a default Lucide icon + a default English aria-label. Override the icon or aria-label per target if you want a different look or different text.
Custom targets
import { Send } from "lucide-react"
<ShareBar
url={article.canonicalUrl}
targets={[
{ kind: "twitter" },
{ kind: "linkedin" },
{
kind: "custom",
id: "send-to-teammate",
icon: Send,
ariaLabel: "Send to teammate",
onClick: () => openInternalShareDialog(article.id),
},
{ kind: "copy" },
]}
/>Analytics hook
<ShareBar
targets={[{ kind: "twitter" }, { kind: "facebook" }, { kind: "copy" }]}
onShare={(target) => analytics.track("article.share", { id: article.id, target })}
/>onShare(targetKind) fires after a successful share-intent open or successful copy. For granular hooks use onCopySuccess / onCopyError.
URL resolution
- If
urlis provided, that's what gets shared. - Otherwise,
window.location.hrefis read at click time on the client — never during render. SSR-safe. - Pass
title/text/via/hashtagsfor templates that accept them (Twitter, Email, WhatsApp, etc.).
Copy fallback
Copy uses navigator.clipboard.writeTextfirst; if that isn't available (older browsers, insecure HTTP context, embedded webviews), it falls back to the deprecated document.execCommand("copy") on a hidden textarea. Both paths are inside a try/catch so the error state surfaces to onCopyError + the icon flip.
Notes
- External links open in a new window with
noopener,noreferrerfor safety. - Copy success/error feedback is dual-channel: visible icon flip +
aria-liveannouncement (politefor success,alertfor errors). - The 2-second success-reset timeout is cleared on unmount — no
setState after unmountwarning. - Threads + Bluesky icons fall back to
Share2from lucide-react until first-party icons land. Override viatarget.iconif you ship custom SVGs. - The component is exported as
React.memo. Memoize thetargetsarray (or use a module-level constant) for the memo to bite — inline arrays defeat it. - Don't reach for this if you need share-count metrics — pure action surface, no API calls.
Features
- 9 built-in platforms with URL templates (Twitter / Facebook / LinkedIn / Reddit / WhatsApp / Telegram / Email / Threads / Bluesky)
- Copy-link button with success/error feedback (icon flip + aria-live)
- Clipboard fallback to document.execCommand for older / insecure browsers
- Custom targets via 'kind: custom' (arbitrary icon + onClick)
- Analytics hook via onShare(targetKind)
- Configurable URL / title / text / via / hashtags
- Optional section heading (h2 / h3 / h4) with i18n labels
- Optional top divider (`pt-8 border-t border-border`)
- External links use target=_blank rel=noopener,noreferrer
- Memoized; SSR-safe; <ul>/<li> semantics