Skip to main content
Back to Blog
Tutorials
3 min read
November 21, 2024

How to Add Social Sharing Buttons to Your Website

Add social sharing buttons for Twitter, Facebook, LinkedIn, and more. No external libraries, just native share URLs.

Ryel Banfield

Founder & Lead Developer

Social sharing buttons let visitors share your content on their networks. Here is how to implement them without any third-party scripts or libraries.

Step 1: Define Share URLs

Each social platform has a share URL format:

// lib/share.ts
export function getShareUrls(url: string, title: string, description?: string) {
  const encodedUrl = encodeURIComponent(url);
  const encodedTitle = encodeURIComponent(title);
  const encodedDescription = encodeURIComponent(description || "");

  return {
    twitter: `https://twitter.com/intent/tweet?url=${encodedUrl}&text=${encodedTitle}`,
    facebook: `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`,
    linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${encodedUrl}`,
    email: `mailto:?subject=${encodedTitle}&body=${encodedDescription}%0A%0A${encodedUrl}`,
    reddit: `https://reddit.com/submit?url=${encodedUrl}&title=${encodedTitle}`,
    hackernews: `https://news.ycombinator.com/submitlink?u=${encodedUrl}&t=${encodedTitle}`,
  };
}

Step 2: Build the Share Buttons Component

import { getShareUrls } from "@/lib/share";

type ShareButtonsProps = {
  url: string;
  title: string;
  description?: string;
};

export function ShareButtons({ url, title, description }: ShareButtonsProps) {
  const shareUrls = getShareUrls(url, title, description);

  const platforms = [
    { name: "Twitter", url: shareUrls.twitter, color: "hover:bg-sky-500" },
    { name: "Facebook", url: shareUrls.facebook, color: "hover:bg-blue-600" },
    { name: "LinkedIn", url: shareUrls.linkedin, color: "hover:bg-blue-700" },
    { name: "Reddit", url: shareUrls.reddit, color: "hover:bg-orange-600" },
    { name: "Email", url: shareUrls.email, color: "hover:bg-gray-600" },
  ];

  return (
    <div className="flex gap-2">
      {platforms.map((platform) => (
        <a
          key={platform.name}
          href={platform.url}
          target={platform.name === "Email" ? "_self" : "_blank"}
          rel="noopener noreferrer"
          className={`flex h-10 w-10 items-center justify-center rounded-full border text-gray-600 transition-colors hover:text-white dark:border-gray-700 dark:text-gray-400 ${platform.color}`}
          aria-label={`Share on ${platform.name}`}
        >
          <ShareIcon name={platform.name.toLowerCase()} />
        </a>
      ))}
    </div>
  );
}

Step 3: Add the Native Web Share API

The Web Share API provides a native share dialog on mobile:

"use client";

import { useState } from "react";

export function NativeShareButton({
  url,
  title,
  description,
}: {
  url: string;
  title: string;
  description?: string;
}) {
  const [copied, setCopied] = useState(false);

  async function handleShare() {
    if (navigator.share) {
      try {
        await navigator.share({ title, text: description, url });
      } catch {
        // User cancelled or share failed
      }
    } else {
      // Fallback: copy to clipboard
      await navigator.clipboard.writeText(url);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    }
  }

  return (
    <button
      onClick={handleShare}
      className="flex items-center gap-2 rounded-lg border px-4 py-2 text-sm font-medium hover:bg-gray-50 dark:border-gray-700 dark:hover:bg-gray-800"
    >
      <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
        <path
          strokeLinecap="round"
          strokeLinejoin="round"
          d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z"
        />
      </svg>
      {copied ? "Copied" : "Share"}
    </button>
  );
}

Step 4: Use in a Blog Post Layout

// app/blog/[slug]/page.tsx
import { ShareButtons } from "@/components/ShareButtons";
import { NativeShareButton } from "@/components/NativeShareButton";

export default async function BlogPost({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const post = await getPost(slug);
  const url = `https://yoursite.com/blog/${slug}`;

  return (
    <article className="mx-auto max-w-3xl px-6 py-12">
      <h1 className="text-4xl font-bold">{post.title}</h1>

      {/* Share bar */}
      <div className="mt-8 flex items-center justify-between border-y py-4 dark:border-gray-700">
        <ShareButtons url={url} title={post.title} description={post.excerpt} />
        <NativeShareButton url={url} title={post.title} description={post.excerpt} />
      </div>

      {/* Post content */}
      <div className="prose mt-8 dark:prose-invert">{/* content */}</div>

      {/* Sticky share bar for long posts */}
      <aside className="fixed bottom-6 left-6 hidden lg:block">
        <div className="flex flex-col gap-2">
          <ShareButtons url={url} title={post.title} />
        </div>
      </aside>
    </article>
  );
}

Step 5: Share Icons

function ShareIcon({ name }: { name: string }) {
  const icons: Record<string, React.ReactNode> = {
    twitter: (
      <svg className="h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
        <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
      </svg>
    ),
    facebook: (
      <svg className="h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
        <path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" />
      </svg>
    ),
    linkedin: (
      <svg className="h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
        <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" />
      </svg>
    ),
    reddit: (
      <svg className="h-4 w-4" fill="currentColor" viewBox="0 0 24 24">
        <path d="M12 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0zm5.01 4.744c.688 0 1.25.561 1.25 1.249a1.25 1.25 0 0 1-2.498.056l-2.597-.547-.8 3.747c1.824.07 3.48.632 4.674 1.488.308-.309.73-.491 1.207-.491.968 0 1.754.786 1.754 1.754 0 .716-.435 1.333-1.01 1.614a3.111 3.111 0 0 1 .042.52c0 2.694-3.13 4.87-7.004 4.87-3.874 0-7.004-2.176-7.004-4.87 0-.183.015-.366.043-.534A1.748 1.748 0 0 1 4.028 12c0-.968.786-1.754 1.754-1.754.463 0 .898.196 1.207.49 1.207-.883 2.878-1.43 4.744-1.487l.885-4.182a.342.342 0 0 1 .14-.197.35.35 0 0 1 .238-.042l2.906.617a1.214 1.214 0 0 1 1.108-.701zM9.25 12C8.561 12 8 12.562 8 13.25c0 .687.561 1.248 1.25 1.248.687 0 1.248-.561 1.248-1.249 0-.688-.561-1.249-1.249-1.249zm5.5 0c-.687 0-1.248.561-1.248 1.25 0 .687.561 1.248 1.249 1.248.688 0 1.249-.561 1.249-1.249 0-.687-.562-1.249-1.25-1.249zm-5.466 3.99a.327.327 0 0 0-.231.094.33.33 0 0 0 0 .463c.842.842 2.484.913 2.961.913.477 0 2.105-.056 2.961-.913a.361.361 0 0 0 .029-.463.33.33 0 0 0-.464 0c-.547.533-1.684.73-2.512.73-.828 0-1.979-.196-2.512-.73a.326.326 0 0 0-.232-.095z" />
      </svg>
    ),
    email: (
      <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
        <path strokeLinecap="round" strokeLinejoin="round" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
      </svg>
    ),
  };

  return icons[name] || null;
}

Open Graph Optimization

Sharing buttons work best when your pages have proper Open Graph tags:

// app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
  const { slug } = await params;
  const post = await getPost(slug);

  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      url: `https://yoursite.com/blog/${slug}`,
      images: [{ url: post.image, width: 1200, height: 630 }],
      type: "article",
    },
    twitter: {
      card: "summary_large_image",
      title: post.title,
      description: post.excerpt,
      images: [post.image],
    },
  };
}

Need Help With Content Distribution?

We build websites optimized for social sharing with proper OG tags, share buttons, and analytics tracking. Contact us to discuss your project.

social sharingNext.jsOpen Graphmarketingtutorial

Ready to Start Your Project?

RCB Software builds world-class websites and applications for businesses worldwide.

Get in Touch

Related Articles