Trying out Shadcn/UI for the first time

I was frustrated when I saw a lot of Tailwind CSS classes in my JSX code. I love Tailwind CSS, but it can be a bit verbose. I recently learned about shadcn/ui, a collection of Tailwind CSS components that can be used to create your own component library. I was surprised to find that shadcn/ui is not a traditional component library. Instead, it provides a set of components and utilities that you can use to create your own components. This makes shadcn/ui a great choice for developers who want to create their own custom component libraries.

Here are some of the benefits of using shadcn/ui:

  • Versatility: shadcn/ui provides a wide range of components and utilities, so you can create a component library that meets your specific needs.

  • Flexibility: shadcn/ui is not a traditional component library, so you have complete control over the look and feel of your components.

  • Efficiency: shadcn/ui can help you to reduce the amount of Tailwind CSS code that you need to write, which can make your code more readable and maintainable.

If you are looking for a way to create your own custom component library, I highly recommend shadcn/ui. It is a powerful tool that can help you to create beautiful and efficient components.

Here is the simple Title component I have created with it.

import * as React from "react"
import { VariantProps, cva } from "class-variance-authority"

import { cn } from "@/lib/utils"

const titleVariants = cva(
  "text-3xl font-extrabold leading-tight tracking-tighter sm:text-3xl md:text-5xl lg:text-6xl",
  {
    variants: {
      variant: {
        default: "",
        h1: "", // Think Something for H1 specific design
        h2: "", // Think Something for H2 specific design
      },
      size: {
        default: "sm:text-3xl md:text-5xl lg:text-6xl",
        sm: "sm:text-2xl md:text-4xl lg:text-5xl",
        lg: "sm:text-4xl md:text-6xl lg:text-7xl",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

export interface TitleProps
  extends React.HTMLAttributes<HTMLHeadingElement>,
    VariantProps<typeof titleVariants> {}

function Title(props: TitleProps) {
  const { variant, size, className, ...rest } = props

  function H1() {
    return (
      <h1
        className={cn(titleVariants({ variant, size, className }))}
        {...rest}
      />
    )
  }
  function H2() {
    return (
      <h2
        className={cn(titleVariants({ variant, size, className }))}
        {...rest}
      />
    )
  }

  let titleComponentMap = {
    h1: <H1 />,
    h2: <H2 />,
    default: <H1 />,
  }

  type ComponentMapKey = keyof typeof titleComponentMap

  return titleComponentMap[variant as ComponentMapKey] || <H1 />
}

export { Title, titleVariants }

And its implementation in the page.tsx looks like

import Link from "next/link"

import { siteConfig } from "@/config/site"
import { buttonVariants } from "@/components/ui/button"
import { Title, titleVariants } from "@/components/ui/title"

export default function IndexPage() {
  return (
    <section className="container grid items-center gap-6 pb-8 pt-6 md:py-10">
      <div className="flex max-w-[980px] flex-col items-start gap-2">
        <Title size="default" variant="h1">
          Beautifully designed components <br className="hidden sm:inline" />
          built with Radix UI and Tailwind CSS.
        </Title>
        <h2 className={titleVariants({ variant: "h2", size: "sm" })}>
          This is H2
        </h2>
        <p className="max-w-[700px] text-lg text-muted-foreground sm:text-xl">
          Accessible and customizable components that you can copy and paste
          into your apps. Free. Open Source. And Next.js 13 Ready.
        </p>
      </div>

      <div className="flex gap-4">
        <Link
          href={siteConfig.links.docs}
          target="_blank"
          rel="noreferrer"
          className={buttonVariants({ size: "lg" })}
        >
          Documentation
        </Link>
        <Link
          target="_blank"
          rel="noreferrer"
          href={siteConfig.links.github}
          className={buttonVariants({ variant: "outline", size: "lg" })}
        >
          GitHub
        </Link>
      </div>
    </section>
  )
}

Have you noticed the following part in the page.tsx page:

        <Title size="default" variant="h1">
          Beautifully designed components <br className="hidden sm:inline" />
          built with Radix UI and Tailwind CSS.
        </Title>
        <h2 className={titleVariants({ variant: "h2", size: "sm" })}>
          This is H2
        </h2>

In the first example, we have used Title component with size and variant props, and in the second example, we have used titleVariants in the className property.

Thank you.