DEV Community

Jithesh
Jithesh

Posted on

πŸš€ React Reusable Social Links Component with Shadcn and Tailwind

I recently created this SocialLinks component while working on my portfolio. It wasn't something I planned to create explicitly, but it turned out to be quite useful! I'm sharing it here so others can benefit from it as well. I'd love to hear your opinions and suggestions on how to improve it. Your feedback is greatly appreciated! 😊

The Component

import React, { forwardRef } from "react";
import { Button } from "./ui/button";
import Link from "next/link";
import { cn } from "@/lib/utils";
import { VariantProps, cva } from "class-variance-authority";

// Styles for the social link container
const socialLinkVariants = cva("flex items-center justify-around", {
  variants: {
    variant: {
      horizontal: "flex-row gap-4 md:gap-6 lg:gap-8",
      vertical: "flex-col gap-4 md:gap-6 lg:gap-8",
    },
    spacing: {
      small: "gap-2 md:gap-3 lg:gap-4",
      medium: "gap-4 md:gap-6 lg:gap-8",
      large: "gap-6 md:gap-8 lg:gap-10",
    },
    padding: {
      none: "p-0",
      small: "p-2 md:p-3 lg:p-4",
      medium: "p-4 md:p-6 lg:p-8",
      large: "p-6 md:p-8 lg:p-10",
    },
  },
  defaultVariants: {
    variant: "horizontal",
    spacing: "medium",
    padding: "none",
  },
});

// Type for individual social link
type SocialLink = {
  href: string;
  label: string;
  icon: React.ReactNode;
};

// Props for the SocialLinks component
type SocialLinksProps = React.DetailedHTMLProps<
  React.HTMLAttributes<HTMLElement>,
  HTMLElement
> &
  VariantProps<typeof socialLinkVariants> & {
    links: SocialLink[];
    buttonSize?: "default" | "sm" | "lg" | "icon";
    buttonVariant?:
      | "link"
      | "default"
      | "destructive"
      | "outline"
      | "secondary"
      | "ghost";
  };

// Forward ref component
const SocialLinks = forwardRef<HTMLElement, SocialLinksProps>(
  (
    {
      variant,
      spacing,
      padding,
      buttonSize = "icon",
      buttonVariant = "link",
      className,
      links,
      ...props
    },
    ref
  ) => {
    return (
      <nav
        ref={ref}
        className={cn(
          socialLinkVariants({ variant, spacing, padding }),
          className
        )}
        {...props}
      >
        {links.map((link, index) => (
          <Button
            key={index}
            asChild
            variant={buttonVariant}
            size={buttonSize}
            className="text-foreground hover:text-primary"
          >
            <Link href={link.href} aria-label={link.label}>
              {link.icon}
            </Link>
          </Button>
        ))}
      </nav>
    );
  }
);

// Set display name for better debugging and readability
SocialLinks.displayName = "SocialLinks";

export default SocialLinks;
Enter fullscreen mode Exit fullscreen mode

Usage

Here's an example of how you can use the SocialLinks component in your project:

import { SocialLinks } from "./components/SocialLinks";
import { Github, Instagram, Linkedin, Twitter } from "lucide-react";

const socialLinks = [
  { href: "https://twitter.com/yourprofile", label: "Twitter", icon: <Twitter /> },
  { href: "https://instagram.com/yourprofile", label: "Instagram", icon: <Instagram /> },
  { href: "https://linkedin.com/in/yourprofile", label: "LinkedIn", icon: <Linkedin /> },
  { href: "https://github.com/yourprofile", label: "GitHub", icon: <Github /> },
];

const App = () => (
  <div>
    <SocialLinks links={socialLinks} />
  </div>
);

export default App;
Enter fullscreen mode Exit fullscreen mode

Feedback

I'd love to hear your opinions and suggestions! Please feel free to reach out to me on Twitter, LinkedIn, or drop a comment below.


Check out the GitHub Gist for the complete code.

Thanks for reading and happy coding! πŸš€

Top comments (0)