JSTAcademy
0 XP
Dashboard
Crash Courses
Component Patterns
11 min
Masters+175 XP
Crash Courses · Masters

Component Patterns

Build reusable, composable UI components using Tailwind utility patterns.
11 min read+175 XP on completionCert: Tailwind CSS Crash Course
Tap any word in the text below to start reading from there.

Component Patterns

In Tailwind, components live in your component files â€" not CSS. Extract via React components with variant props.

Button Component with Variants

import { cn } from '@/lib/utils'
import { cva, type VariantProps } from 'class-variance-authority'

const buttonVariants = cva(
  // base
  "inline-flex items-center justify-center rounded-lg font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none",
  {
    variants: {
      variant: {
        primary: "bg-amber-500 text-white hover:bg-amber-600 focus:ring-amber-500",
        secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-500",
        ghost: "hover:bg-gray-100 text-gray-700",
        destructive: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500",
      },
      size: {
        sm: "h-8 px-3 text-sm",
        md: "h-10 px-4 text-sm",
        lg: "h-12 px-6 text-base",
      },
    },
    defaultVariants: { variant: "primary", size: "md" },
  }
)

interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {}

export function Button({ className, variant, size, ...props }: ButtonProps) {
  return (
    <button className={cn(buttonVariants({ variant, size }), className)} {...props} />
  )
}

// Usage
<Button variant="primary" size="lg">Start Course</Button>
<Button variant="ghost">Cancel</Button>

Course Card Component

function CourseCard({ course }: { course: Course }) {
  return (
    <div className="
      group bg-white dark:bg-gray-800
      border border-gray-200 dark:border-gray-700
      rounded-2xl overflow-hidden
      hover:shadow-lg hover:-translate-y-0.5
      transition-all duration-200
    ">
      <div className="p-5">
        <div className="flex items-center justify-between mb-3">
          <Badge level={course.level} />
          <span className="text-xs text-gray-500">{course.duration} min</span>
        </div>
        <h3 className="font-semibold text-gray-900 dark:text-white mb-2">
          {course.title}
        </h3>
        <p className="text-sm text-gray-600 dark:text-gray-400 line-clamp-2">
          {course.subtitle}
        </p>
      </div>
      <div className="px-5 pb-4 flex items-center justify-between">
        <span className="text-xs font-medium text-amber-600">{course.xp} XP</span>
        <span className="text-xs text-gray-400">Module {course.module}</span>
      </div>
    </div>
  )
}
0%