Site development in progress.
ndk logondk
Primitives

Social Share

Social media link sharing components.

Shares a url along and a piece of text across a list of social media platforms. On mobile, its opens in the default application for that platform. For example clicking the Email link opens the Gmail application on your phone with some fields auto-filled.

On the web, it opens a separate window to the web application for that platform.

Preview

Loading...

Installation

Install the following dependencies:

npm install lucide-react

Install the following registry dependencies:

npx shadcn@latest add button popover @ndk/components-social-icons

Copy and paste the following code into your project:

components/ndk/_ui/social-share.tsx
"use client";
import React, { createContext, useEffect, useMemo, useState } from "react";

type SocialShareContextType = {
  encodedUrl: string;
  encodedTitle: string;
  encodedDescription: string;
  handleShare: (shareUrl: string) => void;
};

const SocialShareContext = createContext<SocialShareContextType>({
  encodedUrl: "",
  encodedTitle: "",
  encodedDescription: "",
  handleShare: () => {},
});

export type SocialShareRootProps = React.ComponentProps<"div"> & {
  url?: string;
  title?: string;
  description?: string;
};

export function SocialShareRoot({
  url,
  title = "Check this out!",
  description = "I found something interesting to share with you",
  children,
  ...props
}: SocialShareRootProps) {
  const [resolvedUrl, setResolvedUrl] = useState<string>(url ?? "");

  useEffect(() => {
    if (url) {
      setResolvedUrl(url);
    } else if (typeof window !== "undefined") {
      setResolvedUrl(window.location.href);
    }
  }, [url]);

  const encodedUrl = useMemo(
    () => encodeURIComponent(resolvedUrl || ""),
    [resolvedUrl],
  );

  const encodedTitle = useMemo(() => encodeURIComponent(title), [title]);
  const encodedDescription = useMemo(
    () => encodeURIComponent(description),
    [description],
  );

  const handleShare = (shareUrl: string) => {
    if (typeof window !== "undefined") {
      window.open(
        shareUrl,
        "_blank",
        "noopener,noreferrer,width=600,height=600",
      );
    }
  };

  return (
    <SocialShareContext.Provider
      value={{
        encodedUrl,
        encodedTitle,
        encodedDescription,
        handleShare,
      }}
    >
      <div {...props}>{children}</div>
    </SocialShareContext.Provider>
  );
}

export type SocialShareFacebookProps = React.ComponentProps<"button">;

export function SocialShareFacebook({ ...props }: SocialShareFacebookProps) {
  return (
    <SocialShareContext.Consumer>
      {({ encodedUrl, handleShare }) => (
        <button
          {...props}
          onClick={() =>
            handleShare(
              `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`,
            )
          }
        />
      )}
    </SocialShareContext.Consumer>
  );
}

export type SocialShareXTwitterProps = React.ComponentProps<"button">;

export function SocialShareXTwitter({ ...props }: SocialShareXTwitterProps) {
  return (
    <SocialShareContext.Consumer>
      {({ encodedUrl, encodedTitle, handleShare }) => (
        <button
          {...props}
          onClick={() =>
            handleShare(
              `https://twitter.com/intent/tweet?url=${encodedUrl}&text=${encodedTitle}`,
            )
          }
        />
      )}
    </SocialShareContext.Consumer>
  );
}

export type SocialShareLinkedInProps = React.ComponentProps<"button">;

export function SocialShareLinkedIn({ ...props }: SocialShareLinkedInProps) {
  return (
    <SocialShareContext.Consumer>
      {({ encodedUrl, handleShare }) => (
        <button
          {...props}
          onClick={() =>
            handleShare(
              `https://www.linkedin.com/sharing/share-offsite/?url=${encodedUrl}`,
            )
          }
        />
      )}
    </SocialShareContext.Consumer>
  );
}

export type SocialShareWhatsAppProps = React.ComponentProps<"button">;

export function SocialShareWhatsApp({ ...props }: SocialShareWhatsAppProps) {
  return (
    <SocialShareContext.Consumer>
      {({ encodedUrl, encodedTitle, handleShare }) => (
        <button
          {...props}
          onClick={() =>
            handleShare(`https://wa.me/?text=${encodedTitle}%20${encodedUrl}`)
          }
        />
      )}
    </SocialShareContext.Consumer>
  );
}

export type SocialShareTelegramProps = React.ComponentProps<"button">;

export function SocialShareTelegram({ ...props }: SocialShareTelegramProps) {
  return (
    <SocialShareContext.Consumer>
      {({ encodedUrl, encodedTitle, handleShare }) => (
        <button
          {...props}
          onClick={() =>
            handleShare(
              `https://t.me/share/url?url=${encodedUrl}&text=${encodedTitle}`,
            )
          }
        />
      )}
    </SocialShareContext.Consumer>
  );
}

export type SocialShareEmailProps = React.ComponentProps<"button">;

export function SocialShareEmail({ ...props }: SocialShareEmailProps) {
  return (
    <SocialShareContext.Consumer>
      {({ encodedUrl, encodedDescription, encodedTitle, handleShare }) => (
        <button
          {...props}
          onClick={() =>
            handleShare(
              `mailto:?subject=${encodedTitle}&body=${encodedDescription}%0A%0A${encodedUrl}`,
            )
          }
        />
      )}
    </SocialShareContext.Consumer>
  );
}

Update the import paths to match your project setup.

Usage

social-share-usage.tsx
export default () => (
  <SocialShareRoot>
    <SocialShareFacebook />
    <SocialShareWhatsApp />
    <SocialShareXTwitter />
    <SocialShareLinkedIn />
    <SocialShareTelegram />
    <SocialShareEmail />
  </SocialShareRoot>
);

Props

SocialShareRoot

Prop

Type

SocialShareEmail, SocialShareXTwitter...

button-props
type SocialShareEmailProps = React.ComponentProps<"button">,
type SocialShareXTwitterProps = React.ComponentProps<"button">,
//.... the rest also share the same type as above (extend the html button element)

On this page