shadcn/ui Component Reference

Quick reference for the 40+ pre-installed shadcn/ui components.

Documentation: https://ui.shadcn.com/docs/components

Most Used for Landing Pages

ComponentUse CaseExample
ButtonCTAs, actionsHero buttons, form submits
BadgeLabels, status”New”, β€œPopular”, β€œBeta”
CardContent containersFeature cards, pricing tiers
AccordionCollapsible contentFAQ sections
DialogModalsVideo players, signup forms
NavigationMenuHeader navigationMain nav with dropdowns
TabsTabbed contentFeature showcases
CarouselSliding contentTestimonials, galleries

Full Component List

Layout & Navigation

  • Accordion β€” Collapsible sections
  • Breadcrumb β€” Navigation trail
  • Carousel β€” Sliding content
  • Collapsible β€” Expand/collapse
  • NavigationMenu β€” Header nav with dropdowns
  • Pagination β€” Page navigation
  • Resizable β€” Resizable panels
  • Scroll-Area β€” Custom scrollbars
  • Separator β€” Visual divider
  • Sheet β€” Slide-out panels
  • Sidebar β€” App sidebars
  • Tabs β€” Tabbed content

Data Display

  • Avatar β€” User images
  • Badge β€” Labels and status
  • Card β€” Content container
  • HoverCard β€” Hover popups
  • Table β€” Data tables

Forms

  • Button β€” Actions
  • Checkbox β€” Multi-select
  • Combobox β€” Searchable select
  • DatePicker β€” Date selection
  • Form β€” Form wrapper with validation
  • Input β€” Text input
  • InputOTP β€” One-time password
  • Label β€” Form labels
  • RadioGroup β€” Single select
  • Select β€” Dropdown select
  • Slider β€” Range selection
  • Switch β€” Toggle
  • Textarea β€” Multi-line input
  • Toggle β€” Toggle button
  • ToggleGroup β€” Button group

Feedback

  • Alert β€” Info messages
  • AlertDialog β€” Confirmation dialogs
  • Dialog β€” Modal windows
  • Drawer β€” Bottom sheets
  • Popover β€” Popup content
  • Progress β€” Loading bars
  • Skeleton β€” Loading placeholders
  • Sonner β€” Toast notifications
  • Toast β€” Notifications
  • Tooltip β€” Hover hints

Utilities

  • AspectRatio β€” Maintain ratios
  • Calendar β€” Date display
  • Chart β€” Data visualization
  • Command β€” Command palette
  • ContextMenu β€” Right-click menus
  • DropdownMenu β€” Dropdown menus
  • Menubar β€” App menubars

Code Examples

Hero with Badge and Buttons

import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
 
function Hero() {
  return (
    <section className="py-24 text-center">
      <Badge variant="secondary" className="mb-4">
        Now in beta
      </Badge>
      
      <h1 className="text-5xl font-bold mb-6">
        Your headline here
      </h1>
      
      <p className="text-xl text-muted-foreground mb-8 max-w-2xl mx-auto">
        Subheadline with more details about your product.
      </p>
      
      <div className="flex gap-4 justify-center">
        <Button size="lg">Get Started</Button>
        <Button size="lg" variant="outline">Learn More</Button>
      </div>
    </section>
  )
}

Feature Cards

import { Card, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"
import { Zap, Shield, Globe } from "lucide-react"
 
const features = [
  { icon: Zap, title: "Fast", description: "Lightning quick performance" },
  { icon: Shield, title: "Secure", description: "Enterprise-grade security" },
  { icon: Globe, title: "Global", description: "CDN in 200+ locations" },
]
 
function Features() {
  return (
    <section className="py-24">
      <div className="grid md:grid-cols-3 gap-8">
        {features.map((f) => (
          <Card key={f.title}>
            <CardHeader>
              <f.icon className="h-10 w-10 mb-4 text-primary" />
              <CardTitle>{f.title}</CardTitle>
              <CardDescription>{f.description}</CardDescription>
            </CardHeader>
          </Card>
        ))}
      </div>
    </section>
  )
}

Pricing Table

import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Check } from "lucide-react"
 
const plans = [
  { name: "Free", price: 0, features: ["5 projects", "Basic support"] },
  { name: "Pro", price: 19, features: ["Unlimited projects", "Priority support", "API access"], popular: true },
  { name: "Team", price: 49, features: ["Everything in Pro", "Team features", "SSO"] },
]
 
function Pricing() {
  return (
    <section className="py-24">
      <div className="grid md:grid-cols-3 gap-8">
        {plans.map((plan) => (
          <Card key={plan.name} className={plan.popular ? "border-primary" : ""}>
            <CardHeader>
              {plan.popular && <Badge className="w-fit mb-2">Most Popular</Badge>}
              <CardTitle>{plan.name}</CardTitle>
              <CardDescription>
                <span className="text-4xl font-bold">${plan.price}</span>
                <span className="text-muted-foreground">/month</span>
              </CardDescription>
            </CardHeader>
            <CardContent>
              <ul className="space-y-2">
                {plan.features.map((f) => (
                  <li key={f} className="flex items-center gap-2">
                    <Check className="h-4 w-4 text-primary" />
                    {f}
                  </li>
                ))}
              </ul>
            </CardContent>
            <CardFooter>
              <Button className="w-full" variant={plan.popular ? "default" : "outline"}>
                Get Started
              </Button>
            </CardFooter>
          </Card>
        ))}
      </div>
    </section>
  )
}

FAQ Accordion

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion"
 
const faqs = [
  { q: "How does it work?", a: "Our platform uses AI to..." },
  { q: "Is there a free trial?", a: "Yes, you get 14 days free..." },
  { q: "Can I cancel anytime?", a: "Absolutely, no questions asked..." },
]
 
function FAQ() {
  return (
    <section className="py-24 max-w-3xl mx-auto">
      <h2 className="text-3xl font-bold text-center mb-12">
        Frequently Asked Questions
      </h2>
      
      <Accordion type="single" collapsible>
        {faqs.map((faq, i) => (
          <AccordionItem key={i} value={`item-${i}`}>
            <AccordionTrigger>{faq.q}</AccordionTrigger>
            <AccordionContent>{faq.a}</AccordionContent>
          </AccordionItem>
        ))}
      </Accordion>
    </section>
  )
}

Mobile Navigation with Sheet

import { Button } from "@/components/ui/button"
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
import { Menu } from "lucide-react"
 
function MobileNav() {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="ghost" size="icon" className="md:hidden">
          <Menu className="h-6 w-6" />
        </Button>
      </SheetTrigger>
      <SheetContent side="right">
        <nav className="flex flex-col gap-4 mt-8">
          <a href="#features">Features</a>
          <a href="#pricing">Pricing</a>
          <a href="#faq">FAQ</a>
          <Button className="mt-4">Get Started</Button>
        </nav>
      </SheetContent>
    </Sheet>
  )
}

Video Modal with Dialog

import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Play } from "lucide-react"
 
function VideoModal() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button variant="outline" size="lg">
          <Play className="mr-2 h-4 w-4" />
          Watch Demo
        </Button>
      </DialogTrigger>
      <DialogContent className="max-w-4xl p-0">
        <div className="aspect-video">
          <iframe
            src="https://www.youtube.com/embed/..."
            className="w-full h-full"
            allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
            allowFullScreen
          />
        </div>
      </DialogContent>
    </Dialog>
  )
}

Styling Tips

Customizing Colors

shadcn uses CSS variables. Override in your globals.css:

:root {
  --primary: 220 90% 56%;
  --primary-foreground: 0 0% 100%;
  --accent: 25 95% 53%;
}
 
.dark {
  --primary: 220 90% 66%;
}

Extending Variants

// components/ui/button.tsx
const buttonVariants = cva(
  "...",
  {
    variants: {
      variant: {
        default: "...",
        // Add custom variant
        gradient: "bg-gradient-to-r from-primary to-accent text-white hover:opacity-90",
      },
    },
  }
)

Using with Tailwind

All components accept className for additional styling:

<Button className="rounded-full px-8">
  Pill Button
</Button>
 
<Card className="bg-gradient-to-br from-primary/10 to-accent/10">
  Gradient Card
</Card>