English

Hello! Ready to master shadcn/ui? Perfect! I'll be sharing some essential practices that will help you build better, more maintainable UIs with this amazing component library.

These practices come from real-world experience and will help you avoid common pitfalls while maximizing the potential of shadcn/ui.


Component Composition

Start with Base Components

Always begin with shadcn/ui base components and compose them thoughtfully. Don't rush into creating custom variants immediately.

// ✅ Good: Start with base component
import { Button } from '@/components/ui/button';

export function ActionButton({ children, ...props }) {
  return (
    <Button variant="default" size="sm" {...props}>
      {children}
    </Button>
  );
}

Create Semantic Components

Build semantic components that represent your application's domain, not just visual variants.

import { Button } from '@/components/ui/button';
import { LogIn } from 'lucide-react';

export function LoginButton({ isLoading, ...props }) {
  return (
    <Button disabled={isLoading} className="w-full" {...props}>
      <LogIn className="mr-2 h-4 w-4" />
      {isLoading ? 'Signing in...' : 'Sign In'}
    </Button>
  );
}

Styling Strategies

Leverage CSS Variables

Use shadcn/ui's CSS custom properties system for consistent theming across your application.

:root {
  --radius: 0.5rem;

  /* Custom semantic colors */
  --success: 142 76% 36%;
  --warning: 38 92% 50%;
  --error: 0 84% 60%;
}

Extend with Tailwind Variants

Create reusable variants using Tailwind's flexible class system, but keep it organized.

import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';

const statusVariants = {
  success: 'bg-green-600 hover:bg-green-700 text-white',
  warning: 'bg-yellow-600 hover:bg-yellow-700 text-white',
  error: 'bg-red-600 hover:bg-red-700 text-white',
};

export function StatusButton({ status, className, ...props }) {
  return (
    <Button className={cn(statusVariants[status], className)} {...props} />
  );
}

Use Compound Components

For complex UI patterns, create compound components that work together seamlessly.

import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';

export function ProductCard({ children }) {
  return <Card className="overflow-hidden">{children}</Card>;
}

ProductCard.Header = function ProductCardHeader({ title, category }) {
  return (
    <CardHeader className="pb-3">
      <div className="flex items-center justify-between">
        <CardTitle className="text-lg">{title}</CardTitle>
        <Badge variant="secondary">{category}</Badge>
      </div>
    </CardHeader>
  );
};

ProductCard.Content = CardContent;

Form Best Practices

Always Use Form Components Together

shadcn/ui's form components work best when used as a cohesive system.

Do
<Form {...form}>
  <form onSubmit={form.handleSubmit(onSubmit)}>
    <FormField
      control={form.control}
      name="username"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Username</FormLabel>
          <FormControl>
            <Input {...field} />
          </FormControl>
          <FormMessage />
        </FormItem>
      )}
    />
  </form>
</Form>
Don't
<form>
  <label>Username</label>
  <Input name="username" />
  <span className="text-red-500">{error}</span>
</form>

Implement Consistent Validation

Use a consistent validation strategy across all forms in your application.

import { z } from 'zod';

// Define reusable schemas
export const userSchema = z
  .object({
    email: z.string().email('Invalid email address'),
    password: z.string().min(8, 'Password must be at least 8 characters'),
    confirmPassword: z.string(),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: "Passwords don't match",
    path: ['confirmPassword'],
  });

Performance Tips

Import Only What You Need

Don't import the entire components directory. Import specific components to keep your bundle size optimal.

// ✅ Good
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';

// ❌ Avoid
import * as UI from '@/components/ui';

Use React.memo for Heavy Components

For components that render frequently or have expensive calculations, use React.memo.

import { memo } from 'react';
import { Card, CardContent } from '@/components/ui/card';

export const DataCard = memo(function DataCard({ data }) {
  const processedData = useMemo(() => expensiveDataProcessing(data), [data]);

  return (
    <Card>
      <CardContent>
        {processedData.map((item) => (
          <div key={item.id}>{item.value}</div>
        ))}
      </CardContent>
    </Card>
  );
});

Organization Tips

Create a Design System

Establish component variants and patterns early in your project.

// lib/component-variants.ts
export const buttonVariants = {
  primary: 'bg-primary text-primary-foreground hover:bg-primary/90',
  success: 'bg-green-600 text-white hover:bg-green-700',
  danger: 'bg-red-600 text-white hover:bg-red-700',
};

export const cardVariants = {
  elevated: 'shadow-lg border-0',
  flat: 'shadow-none border',
  interactive: 'hover:shadow-md transition-shadow cursor-pointer',
};

Document Your Components

Add proper TypeScript types and JSDoc comments for better developer experience.

interface ProductCardProps {
  /** Product data to display */
  product: Product;
  /** Callback when product is selected */
  onSelect?: (product: Product) => void;
  /** Show compact version */
  compact?: boolean;
  /** Additional CSS classes */
  className?: string;
}

/**
 * Displays product information in a card format
 * Supports both compact and full layouts
 */
export function ProductCard({
  product,
  onSelect,
  compact = false,
  className,
}: ProductCardProps) {
  // Component implementation
}

These practices will help you build more maintainable and scalable applications with shadcn/ui. Remember, consistency is key – establish patterns early and stick to them throughout your project!

The beauty of shadcn/ui lies in its flexibility while maintaining design consistency. Use these practices as a foundation, but don't be afraid to adapt them to your specific project needs.

0
0
0
0