Learn how to set up a modern Next.js application with shadcn/ui components, TypeScript, and Tailwind CSS for beautiful, accessible UIs.
Welcome to this comprehensive guide on building modern web applications with Next.js and shadcn/ui!
In this tutorial, we'll cover setting up a Next.js project, installing shadcn/ui, and building your first components with TypeScript and Tailwind CSS.
shadcn/ui is a collection of reusable components built using Radix UI and Tailwind CSS. Unlike traditional component libraries, shadcn/ui copies components directly into your project, giving you full control over customization.
Since shadcn/ui components are copied into your project, you can modify them directly. This means no locked-in dependencies and complete freedom to customize!
npx create-next-app@latest my-app --typescript --tailwind --app
cd my-app
Make sure to select "Yes" for the App Router when prompted. This tutorial uses the latest Next.js App Router architecture.
npx shadcn@latest init
This will create a components.json configuration file and set up the necessary utilities.
npx shadcn@latest add button
Now you can use the button component in your app:
import { Button } from "@/components/ui/button";
export default function Home() {
return <Button>Click me</Button>;
}
The components use CSS variables for theming, making it easy to support dark mode:
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
}
Let's create a simple form with validation using React Hook Form and Zod:
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
const formSchema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
});
export function SignupForm() {
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
});
const onSubmit = (values: z.infer<typeof formSchema>) => {
console.log(values);
};
return (
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
<div>
<Label htmlFor="email">Email</Label>
<Input id="email" type="email" placeholder="john@example.com" />
</div>
<div>
<Label htmlFor="password">Password</Label>
<Input id="password" type="password" />
</div>
<Button type="submit">Sign up</Button>
</form>
);
}
shadcn/ui Button component comes with several variants:
<Button variant="default">Default</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
| Component | Use Case | Import |
|---|---|---|
| Button | Interactive actions | @/components/ui/button |
| Card | Grouped content sections | @/components/ui/card |
| Input | Form text input | @/components/ui/input |
| Dialog | Modal dialogs | @/components/ui/dialog |
| Alert | Messages and notices | @/components/ui/alert |
| Form | Form with validation | @/components/ui/form |
You now have everything you need to start building beautiful, accessible interfaces with Next.js and shadcn/ui. Check out the other blog posts for more advanced patterns!
shadcn/ui provides a fantastic foundation for building beautiful, accessible interfaces. Copy the components into your project and customize them to fit your needs!
Happy coding!