Shadcn with NextJS, Tailwind, Yarn on MacOS (2024)
Want to get Shadcn running with NextJS, Tailwind, and yarn?? You’ve come to the right place in 2024.
Got Node?
Be sure to have the right node version installed and use nvm
to reduce your confusion. This was the correct one in 2024 of August for me.
nvm install 20.9.0
nvm use 20.9.0
Make a NextJS app
You can either keep it simple (JS) or make it more complex (TS + linter).
yarn create next-app . --tailwind
yarn create next-app . --tailwind --typescript --eslint
Throw in Shadcn
You get a wizard once you cast the shadcn spell.
npx shadcn@latest init
Go ahead and yarn
I’m so used to doing npm
but I know yarn
makes me cooler.
yarn dev
Add a fancy shadcn component
I’m partial to terms of services checkboxes so …
npx shadcn@latest add checkbox
Then go to src/app/page.js
and add in the sample code you found on the checkbox page over at shadcn/ui.
You get a new Vercel advert like below.
Leverage the magic of Tailwind
You can mess with the classes and create a checkbox like this:
With the restyling of the Checkbox’s CSS that uses Tailwind.
...
<div className="flex items-center space-x-3">
<Checkbox
id="terms"
className="h-5 w-5 text-blue-500 border-gray-300 rounded focus:ring-blue-500 focus:ring-2 dark:text-blue-500 dark:border-gray-600 dark:focus:ring-blue-500 hover:border-blue-700 hover:bg-blue-100"
/>
<label
htmlFor="terms"
className="text-sm font-medium text-gray-900 dark:text-gray-300 cursor-pointer"
>
Accept terms and conditions
</label>
</div>
...
What else can you do?
I saw a demo of the Sonner
component on YouTube the other day and definitely wanted it for myself. I can’t resist a beautiful toast. Go and get a button component, and also the sonner component.
npx shadcn@latest add button
npx shadcn@latest add sonner
You’ll need to change the components/ui/button.jsx
at the very top.
And modify your src/app/layout.js
to add the Toaster reference.
import { Inter } from "next/font/google";
import "./globals.css";
import { Toaster } from 'sonner';
const inter = Inter({ subsets: ["latin"] });
export const metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>
<Toaster />
{children}</body>
</html>
);
}
Lastly, let’s stop pretending we’re a Vercel advert and change page.js
.
'use client';
import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<Button
variant="outline"
onClick={() => {
console.log("Button clicked");
toast("Event has been created", {
description: "Sunday, December 03, 2023 at 9:00 AM",
action: {
label: "Undo",
onClick: () => console.log("Undo clicked"),
},
});
}}
>
Show Toast
</Button>
</main>
);
}
And then you get something pretty wonderful.
What to do next?
Now that I’ve figured this out, I definitely need to do some more stuff. I hope this works for you! My repo is over here. —JM