principle | Description | Example |
---|---|---|
Utility-First | Use Tailwind's utility classes instead of custom CSS |
|
Component Composition | Design for composition with className overrides |
|
Theme Consistency | Use DaisyUI's semantic color system |
|
Responsive Design | Mobile-first layouts with breakpoint prefixes |
|
Accessibility | Ensure proper contrast and focus states |
|
Use Tailwind's utility classes instead of custom CSS
className='p-4 bg-base-100'
Design for composition with className overrides
Accept className prop in components
Use DaisyUI's semantic color system
bg-primary text-primary-content
Mobile-first layouts with breakpoint prefixes
flex flex-col md:flex-row
Ensure proper contrast and focus states
focus:ring-2 focus:ring-primary
import { clsx } from "@akanjs/client";
// Basic usage
<div className={clsx(
"base-classes",
condition && "conditional-classes",
className
)}>
{/* Content */}
</div>
// Object syntax
<div className={clsx(
"base-styles",
{
"bg-primary": isPrimary,
"bg-secondary": isSecondary,
"bg-error": isError,
},
className
)}>
{/* Content */}
</div>
interface CardProps {
className?: string;
}
export const Card = ({ className }: CardProps) => (
<div className={clsx("card bg-base-100 shadow-md", className)}>
{/* Content */}
</div>
);
Option | Type | Default | Description | Example |
---|---|---|---|---|
primary | color | theme-defined | Primary brand color |
|
secondary | color | theme-defined | Secondary brand color |
|
base-100 | color | theme-defined | Base background color |
|
Primary brand color
bg-primary text-primary-content
Secondary brand color
bg-secondary text-secondary-content
Base background color
bg-base-100 text-base-content
<div className="flex flex-col gap-4 md:flex-row">
<div className="w-full md:w-1/3">Sidebar</div>
<div className="w-full md:w-2/3">Main Content</div>
</div>
<button className="
bg-primary
hover:bg-primary-focus
focus:ring-2 focus:ring-primary
active:scale-95
disabled:opacity-50
">
Interactive Button
</button>
<div className="space-y-4 p-4">
<div>Section 1</div>
<div>Section 2</div>
<div>Section 3</div>
</div>
export const Card = ({ className, project }: CardProps) => (
<Link
href={href}
className={clsx(
"border-base-300 bg-base-100 flex flex-col gap-3 rounded-lg border-2 p-4",
"hover:border-primary transition-all hover:shadow-md",
className
)}
>
<h3 className="text-base-content text-lg font-semibold">
{project.name}
</h3>
</Link>
);
export const Detail = ({ className, project }: ViewProps) => (
<div className={clsx("bg-base-100 rounded-lg p-6 shadow-lg", className)}>
<div className="border-primary mb-6 border-l-4 pl-4">
<h1 className="text-primary text-2xl font-bold">{project.name}</h1>
</div>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
{/* Content */}
</div>
</div>
);
export const Form = ({ className }: { className?: string }) => (
<div className={clsx("card bg-base-100 p-6 shadow-lg", className)}>
<h2 className="card-title mb-4">Project Details</h2>
<div className="form-control w-full">
<label className="label">
<span className="label-text">Project Name</span>
</label>
<input
type="text"
className="input input-bordered w-full"
value={project.name}
/>
</div>
</div>
);
export const StatusBadge = ({ status }: { status: string }) => (
<span className={clsx(
"badge font-medium",
status === "active" && "badge-success",
status === "pending" && "badge-warning",
status === "error" && "badge-error"
)}>
{status}
</span>
);
export const Dashboard = ({ className }: { className?: string }) => (
<div className={clsx("grid grid-cols-1 gap-6 lg:grid-cols-3", className)}>
<div className="lg:col-span-2"><ProjectSummary /></div>
<div><ProjectStats /></div>
<div className="lg:col-span-3"><ProjectTimeline /></div>
</div>
);
<div className="card bg-base-100 shadow-md transition-shadow hover:shadow-lg">
<figure className="px-4 pt-4">
<img src={image} className="rounded-lg object-cover h-48 w-full" />
</figure>
<div className="card-body">
<h2 className="card-title">{title}</h2>
<p className="text-base-content/70">{description}</p>
<div className="card-actions mt-4 justify-end">
<button className="btn btn-primary btn-sm">View Details</button>
</div>
</div>
</div>
<div className="form-control w-full max-w-md">
<label className="label">
<span className="label-text">Email</span>
</label>
<input type="email" className="input input-bordered w-full" />
<label className="label">
<span className="label-text-alt text-error">Error message</span>
</label>
</div>
best-practice | Description | Example |
---|---|---|
Component Composition | Create small, focused components combined to build complex UIs |
|
Color Usage | Use DaisyUI theme colors with proper contrast ratios |
|
Dark Mode | Leverage automatic dark mode adaptation |
|
Create small, focused components combined to build complex UIs
Compose <Card> + <Header> + <Body>
Use DaisyUI theme colors with proper contrast ratios
text-primary bg-base-100
Leverage automatic dark mode adaptation
bg-base-100 text-base-content
mistake | Description | Example |
---|---|---|
Hardcoded Colors | Using hex codes instead of theme variables |
|
Missing className | Not forwarding className prop for composition |
|
Inconsistent Spacing | Mixing arbitrary values instead of Tailwind's scale |
|
Using hex codes instead of theme variables
bg-[#3b82f6] instead of bg-primary
Not forwarding className prop for composition
Component without className prop
Mixing arbitrary values instead of Tailwind's scale
m-2 vs m-[8px]
Option | Type | Default | Description | Example |
---|---|---|---|---|
styles-not-applying | issue | - | Check class name typos and Tailwind configuration |
|
daisyui-components | issue | - | Verify DaisyUI installation and theme config |
|
responsive-issues | issue | - | Test breakpoints and use mobile-first approach |
|
Check class name typos and Tailwind configuration
Verify tailwind.config.js
Verify DaisyUI installation and theme config
npx daisyui@latest init
Test breakpoints and use mobile-first approach
Use md: lg: xl: prefixes