Introduction
As a React developer, you may be tired of writing custom components from scratch or dealing with rigid UI libraries like Material UI or Ant Design. Meet ShadCN UI: a sleek, minimal, and customizable component library built on Tailwind CSS and Radix UI. Whether you're building a dashboard, an e-commerce platform, or a SaaS application, ShadCN UI provides elegant, accessible, and developer-friendly components to speed up your workflow.
In this blog, we’ll explore why ShadCN UI stands out, how to integrate it, and how to make the most of its features. Let’s dive in! 🚀
About ShadCN
If you've ever struggled with UI libraries that lack flexibility or require complex overrides, ShadCN UI offers a refreshing alternative, providing flexibility and ease of customization.
ShadCN UI is not a typical component library—it's more like a collection of pre-built, customizable components that live inside your project, giving you complete control. It is built on Tailwind CSS for styling and Radix UI for accessibility and interactions, ensuring a smooth developer experience.
Unlike traditional UI libraries that impose strict design constraints, ShadCN UI is unopinionated, allowing you to style and extend components freely.
Setting up ShadCN with NextJS project
First, let's setup a NextJS project
npx create-next-app@latest
On installation, you'll see the following prompts:
What is your project named? my-app
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like your code inside a `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to use Turbopack for `next dev`? No / Yes
Would you like to customize the import alias (`@/*` by default)? No / Yes
What import alias would you like configured? @/*
After the prompts, create-next-app
will create a folder with your project name and install the required dependencies.
Now, let's setup ShadCN UI by running this command:
# using npm or yarn
npx shadcn-ui@latest init
# using pnpm
pnpm dlx shadcn@latest init
# using bun
bunx --bun shadcn@latest init
This command will set up the necessary dependencies and configurations.
Now, you can add individual components in your project.
# using npm or yarn
npx shadcn@latest add button
# using pnpm
pnpm dlx shadcn@latest add button
# using bun
bunx --bun shadcn@latest add button
The command above will add the Button component to your project. You can then import it like this:
import { Button } from "@/components/ui/button"
export default function Home() {
return (
<div>
<Button>Click me</Button>
</div>
)
}
Customizing ShadCN Components
Since ShadCN UI is a file based library, all components are stored in your project and you can freely customize them.
Customize the Button Component
Navigate to components/ui/button.tsx and update the styles:
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
outline:
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-md px-3 text-xs",
lg: "h-10 rounded-md px-8",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }
Now you have full control over the component’s styling and behavior!
Building a Simple UI with ShadCN
Let's build a login form using ShadCN components
"use client";
import React from "react";
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
// define signin form schema using zod
const formSchema = z.object({
email: z.string().email({
message: "Invalid email address!",
}),
password: z.string().min(2, {
message: "Password required!",
}),
});
const SignIn: React.FC<SignInProps> = ({}) => {
// Define your form
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
email: "",
password: "",
},
});
// Define a submit handler
function onSubmit(values: z.infer<typeof formSchema>) {
console.log(values)
}
return (
<div className="flex items-center justify-center w-full h-screen bg-primary bg-opacity-5">
<Card className="w-[35%] sm:p-4 p-3 rounded-lg shadow-xl">
<CardHeader className="mb-6">
<CardTitle className="text-3xl font-bold text-center">
Sign In
</CardTitle>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel className="text-lg font-medium">Email</FormLabel>
<FormControl>
<Input
type="email"
placeholder="Email"
className="border-gray-400 py-2 focus-visible:ring-primary text-lg"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem className="w-full">
<FormLabel className="text-lg font-medium">
Password
</FormLabel>
<FormControl>
<Input
type="password"
placeholder="Password"
className="border-gray-400 py-2 focus-visible:ring-primary text-lg"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="w-full flex justify-center">
<Button
type="submit"
className="bg-primary text-white py-2 px-3 mt-2 font-medium text-lg w-full"
>
Sign In
</Button>
</div>
</form>
</Form>
</CardContent>
</Card>
</div>
);
};
export default SignIn;
interface SignInProps {}
This form is lightweight, fully customizable, and follows accessibility best practices!
Conclusion
ShadCN UI is a game-changer for developers who love Tailwind CSS and customizability. It provides a flexible alternative to bulky UI libraries while ensuring accessibility and modern design. If you're building a React app, give ShadCN UI a try—it might become your go-to component library!
🚀 Ready to explore more?
Check out the official ShadCN UI docs and start building stunning UIs today!
Happy coding! 🎉