Style React components with Tailwind utility classes — including conditional styles — and build on shadcn/ui components you own and can restyle freely.
Why: utility classes live right on the element, and because className is just a string you can compute it — conditional styles become ordinary JavaScript. Note: the Tailwind course covers the utilities themselves; this is the React side of the workflow.
export default function Alert({ kind }: { kind: 'info' | 'error' }) {
return (
// className is just a string — build it with ordinary JavaScript
<div
className={
'rounded-lg border p-4 text-sm ' + // classes every alert shares
(kind === 'error' // + one set or the other
? 'border-red-300 bg-red-50 text-red-800'
: 'border-blue-300 bg-blue-50 text-blue-800')
}
>
{kind === 'error' ? 'Something went wrong.' : 'Heads up!'}
</div>
)
}Why: instead of installing a component library you cannot change, shadcn/ui copies accessible components — built on Radix primitives, styled with Tailwind — into your project. You own the code; restyle or rewrite anything.
$ pnpm dlx shadcn@latest init$ pnpm dlx shadcn@latest add button dialog// The components are copied into YOUR project — open and edit them freely
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
export default function DeleteAccount() {
return (
<Dialog>
{/* asChild lets the Button itself act as the thing that opens the dialog */}
<DialogTrigger asChild>
<Button variant="destructive">Delete account</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
</DialogHeader>
<Button variant="outline">Cancel</Button>
</DialogContent>
</Dialog>
)
}