The Button component is the most used element in any React application. shadcn/ui's Button gives you a solid foundation — all variants, sizes and states handled — that you own and can customise directly in your codebase.
Installation
# Initialize shadcn/ui if you haven't already
npx shadcn@latest init
# Add the Button component
npx shadcn@latest add button
This creates components/ui/button.tsx in your project. Unlike npm packages, you own this file — modify it however you need.
Usage
import { Button } from "@/components/ui/button"
export default function MyPage() {
return <Button>Click me</Button>
}
Props Reference
| Prop | Type | Default | Description |
|---|---|---|---|
variant | default | secondary | destructive | outline | ghost | link | default | Visual style |
size | default | sm | lg | icon | default | Button size |
disabled | boolean | false | Disables the button |
asChild | boolean | false | Renders as child element (useful for links) |
className | string | — | Additional Tailwind classes |
1. Button Variants
All shadcn/ui button variants — default, secondary, destructive, outline, ghost and link.
import { Button } from "@/components/ui/button"
export default function ButtonVariants() {
return (
<div className="flex flex-wrap gap-3">
<Button>Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
</div>
)
}2. Button Sizes
shadcn/ui buttons come in sm, default and lg sizes. Use size prop to control.
import { Button } from "@/components/ui/button"
export default function ButtonSizes() {
return (
<div className="flex flex-wrap items-center gap-3">
<Button size="sm">Small</Button>
<Button>Default</Button>
<Button size="lg">Large</Button>
<Button size="icon" aria-label="Settings">
⚙️
</Button>
</div>
)
}3. Buttons with Icons
Buttons with Lucide React icons. Use gap-2 to space the icon and text.
import { Button } from "@/components/ui/button"
import { Download, Trash2, Plus, ArrowRight, Github } from "lucide-react"
export default function ButtonWithIcons() {
return (
<div className="flex flex-wrap gap-3">
<Button>
<Download className="mr-2 h-4 w-4" />
Download
</Button>
<Button variant="destructive">
<Trash2 className="mr-2 h-4 w-4" />
Delete
</Button>
<Button variant="outline">
<Plus className="mr-2 h-4 w-4" />
Add New
</Button>
<Button variant="secondary">
Continue
<ArrowRight className="ml-2 h-4 w-4" />
</Button>
<Button variant="ghost" className="gap-2">
<Github className="h-4 w-4" />
GitHub
</Button>
</div>
)
}4. Button States
Disabled and loading button states. Use disabled prop or add a spinner for loading.
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { Loader2 } from "lucide-react"
export default function ButtonStates() {
const [loading, setLoading] = useState(false)
const handleClick = () => {
setLoading(true)
setTimeout(() => setLoading(false), 2000)
}
return (
<div className="flex flex-wrap gap-3">
{/* Disabled */}
<Button disabled>Disabled</Button>
<Button variant="outline" disabled>Disabled Outline</Button>
{/* Loading with spinner */}
<Button onClick={handleClick} disabled={loading}>
{loading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Saving...
</>
) : (
"Save Changes"
)}
</Button>
{/* Always loading */}
<Button variant="secondary" disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Processing
</Button>
</div>
)
}5. Custom Tailwind Buttons
Buttons built with pure Tailwind CSS classes — no shadcn/ui required. Full control over styling.
export default function TailwindButtons() {
return (
<div className="flex flex-wrap gap-3">
{/* Brand red button */}
<button className="bg-[#fd4766] hover:bg-[#e03355] text-white font-semibold px-4 py-2 rounded-md transition-colors">
Brand Button
</button>
{/* Gradient button */}
<button className="bg-gradient-to-r from-[#fd4766] to-[#4f6ef7] hover:opacity-90 text-white font-semibold px-4 py-2 rounded-md transition-opacity">
Gradient
</button>
{/* Pill button */}
<button className="bg-slate-900 hover:bg-slate-700 text-white font-medium px-6 py-2 rounded-full transition-colors">
Pill Button
</button>
{/* Outline custom */}
<button className="border-2 border-[#fd4766] text-[#fd4766] hover:bg-[#fd4766] hover:text-white font-medium px-4 py-2 rounded-md transition-all">
Custom Outline
</button>
{/* Ghost with hover */}
<button className="text-slate-600 hover:text-slate-900 hover:bg-slate-100 font-medium px-4 py-2 rounded-md transition-all">
Ghost
</button>
</div>
)
}/* Pure Tailwind — no dependencies needed */
export default function PureTailwindButton() {
return (
<button className="
inline-flex items-center justify-center
bg-[#fd4766] hover:bg-[#e03355]
text-white font-semibold
px-4 py-2 rounded-md
transition-colors duration-200
focus:outline-none focus:ring-2 focus:ring-[#fd4766] focus:ring-offset-2
disabled:opacity-50 disabled:cursor-not-allowed
">
Click me
</button>
)
}Frequently Asked Questions
Need a Full React + Next.js Dashboard Template?
Get a complete React + Next.js dashboard with 50+ components — built by the same team behind BootstrapPlanet.
Browse Templates →Use code FIRST30 for 30% off.