shadcn/ui Setup Guide
This document describes how shadcn/ui is configured in the LandlordX frontend application.
Overview
shadcn/ui is a collection of re-usable components built with Radix UI and Tailwind CSS. Unlike traditional component libraries, shadcn/ui components are copied directly into your project, giving you full ownership and control.
Configuration
Files
components.json: Main configuration file for shadcn/ui CLIsrc/lib/utils.ts: Contains thecn()utility function for class mergingsrc/app/globals.css: CSS variables and theming configurationtailwind.config.ts: Tailwind CSS configuration (minimal for v4)
Dependencies
The following packages are installed to support shadcn/ui:
class-variance-authority: For creating component variantsclsx: For conditional class namestailwind-merge: For merging Tailwind classes without conflictslucide-react: Icon library used by shadcn/ui componentstailwindcss-animate: Animation utilities (dev dependency)
Usage
Adding Components
To add a new component from the shadcn/ui library:
# From the root directory
pnpm --filter frontend ui:add <component-name>
# Or from the frontend directory
pnpm ui:add <component-name>Examples:
pnpm ui:add button
pnpm ui:add card
pnpm ui:add dialog
pnpm ui:add dropdown-menuUsing Components
After adding a component, import it using the @/ui alias:
import { Button } from "@repo/ui/button";
import { Card, CardHeader, CardTitle, CardContent } from "@repo/ui/card";
export default function MyPage() {
return (
<Card>
<CardHeader>
<CardTitle>Welcome</CardTitle>
</CardHeader>
<CardContent>
<Button variant="default">Click me</Button>
<Button variant="outline">Cancel</Button>
</CardContent>
</Card>
);
}Using the cn() Utility
The cn() utility function from @/lib/utils intelligently merges Tailwind CSS classes:
import { cn } from "@/lib/utils";
function MyComponent({ className, isActive }) {
return (
<div
className={cn(
"base-styles rounded-md p-4",
isActive && "bg-primary text-primary-foreground",
className,
)}
>
Content
</div>
);
}Theming
Light and Dark Mode
The application supports both light and dark themes. The theme is controlled by adding or removing the .dark class on the root element (typically <html>).
CSS variables are defined in src/app/globals.css:
- Root variables (
:root) define the light theme - Dark mode variables (
.dark) define the dark theme
Customizing Colors
To customize the design system, edit the CSS variables in src/app/globals.css:
:root {
--background: 0 0% 100%; /* HSL values */
--foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
/* ... other variables */
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--primary: 0 0% 98%;
/* ... other variables */
}Radius
Border radius is controlled by the --radius variable:
:root {
--radius: 0.5rem; /* Default radius */
}This value is used throughout the components for consistent rounding.
Tailwind CSS v4 Integration
The project uses Tailwind CSS v4, which has a different syntax from v3:
- Uses
@import "tailwindcss"instead of@tailwinddirectives - Uses
@themedirective for defining design tokens - CSS variables are mapped in the
@themeblock
The integration between shadcn/ui (which expects certain class names) and Tailwind v4 is handled by:
- Defining CSS variables in standard format (
:rootand.dark) - Mapping them to Tailwind’s color system in the
@themeblock - Using HSL color format for maximum flexibility
Component Customization
All shadcn/ui components are added to src/components/ui/ and become part of your codebase. This means:
- You own the code: Modify components directly to fit your needs
- No version lock-in: Components don’t update automatically
- Full customization: Change styles, behavior, or structure as needed
- Type-safe: All components are fully typed with TypeScript
Example of customizing a component:
// src/components/ui/button.tsx
// You can modify the variants, add new ones, or change default styles
const buttonVariants = cva("inline-flex items-center justify-center...", {
variants: {
variant: {
default: "bg-primary text-primary-foreground...",
// Add your custom variant
brand: "bg-gradient-to-r from-blue-500 to-purple-500 text-white",
},
// ...
},
});Best Practices
- Use the cn() utility: Always use
cn()for merging classes to avoid conflicts - Keep components in ui/: Don’t modify the location of shadcn/ui components
- Use semantic color tokens: Use
bg-primaryinstead ofbg-gray-900for consistency - Leverage variants: Use the built-in variant props rather than overriding styles
- Test in both themes: Always check components in light and dark mode
Available Components
For a full list of available components, see the shadcn/ui documentation.
Popular components include:
- Accordion
- Alert Dialog
- Avatar
- Badge
- Button
- Card
- Checkbox
- Dialog
- Dropdown Menu
- Form
- Input
- Label
- Select
- Sheet
- Table
- Tabs
- Toast
- Tooltip
Troubleshooting
Component not found after adding
Make sure the import path uses the @/ui alias:
import { Button } from "@repo/ui/button"; // Correct
import { Button } from "@repo/ui/button"; // Avoid
import { Button } from "../components/ui/button"; // AvoidStyles not applying
- Ensure
globals.cssis imported in your root layout - Check that CSS variables are defined in both
:rootand.dark - Verify Tailwind is processing your component files (check
tailwind.config.tscontent paths)
Dark mode not working
- Ensure the
.darkclass is toggled on the<html>element - Verify dark mode variables are defined in
globals.css - Check that components use semantic color tokens (not hardcoded colors)