Shadcn Button
React button component with variants and loading states. Built with TypeScript and Tailwind CSS for Next.js applications using class-variance-authority.
Button styling not working?
Join our Discord community for help from other developers.
Ever worked on a team where every developer creates their own button style? Primary here, accent there, padding all over the place. Before you know it, your app has 47 different button styles and users have no idea what's clickable. This shadcn/ui button brings order to the chaos.
Button showcase
All button variants that actually make sense:
Built with class-variance-authority (CVA) for type-safe variants and TypeScript autocompletion. Uses Radix UI Slot so it works with any framework's Link component. Styled with Tailwind CSS because inline styles are where dreams go to die.
npx shadcn@latest add button
Why buttons actually drive action
Here's the thing—buttons aren't just rectangles you click. They're decision points. Every button asks users to commit to something: submit this form, delete that file, buy this product. The wrong button style at the wrong time kills conversions.
Think about it: a subtle ghost button for "Delete Account"? Users might click it by accident. A tiny secondary button for "Checkout"? Say goodbye to sales. Button hierarchy isn't just design—it's psychology.
This free shadcn button handles the visual consistency while you focus on the user journey. Whether you're building forms, modals, or navigation in your JavaScript apps, buttons that look and behave predictably build user confidence.
Common button patterns you'll actually use
Button sizes
From compact to prominent for different contexts:
Icon buttons
Space-efficient buttons for toolbars and actions:
Buttons with icons
Combining text with visual reinforcement:
Loading states
Show progress during async operations:
Features
This free open source button component includes everything you need:
- TypeScript variants - Type-safe props with full IntelliSense support
- CVA powered - Consistent variants without the className soup
- Tailwind CSS utilities - Override anything without !important hacks
- Radix UI Slot - Works as Link, button, or any clickable element
- Accessible by default - Keyboard navigation and ARIA support built-in
- Loading states - Built-in disabled state during async operations
- Size flexibility - From tiny icon buttons to large CTAs
API Reference
Button Props
Prop | Type | Default | Description |
---|---|---|---|
variant | "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "default" | Visual style variant |
size | "default" | "sm" | "lg" | "icon" | "default" | Button size preset |
asChild | boolean | false | Render as child component |
disabled | boolean | false | Disabled state |
Variant Guide
Variant | When to Use | Example |
---|---|---|
default | Primary actions | Save, Submit, Continue |
secondary | Alternative actions | Cancel, Back, Reset |
destructive | Dangerous actions | Delete, Remove, Destroy |
outline | On colored backgrounds | Cards, headers, sections |
ghost | Minimal emphasis | Close, More options |
link | Navigation styled as link | Learn more, View details |
Production tips
Primary buttons should be obvious. This free shadcn/ui button defaults to a solid color for a reason. Users should instantly know what the main action is. One primary button per view—not three, not five, ONE.
Ghost buttons aren't invisible. They still need proper contrast and hover states. Your React button might look cool all subtle, but if users can't find it, it's useless. Test on actual screens, not just your monitor.
Loading states prevent rage clicks. When users click "Submit" and nothing happens, they click again. And again. Show a spinner, disable the button, do something. This TypeScript component makes it easy—just toggle disabled during async operations.
Touch targets matter on mobile. That tiny "sm" size looks great on desktop. On mobile? Good luck hitting it with a thumb. Minimum 44px height for touch—this open source shadcn component handles it with proper size variants.
Test button text at different widths. "OK" fits everywhere. "Download Financial Report for Q3 2024" doesn't. Your Next.js app needs buttons that handle both. Set max-widths or let text wrap—just plan for it.
Integration with other components
Buttons are the workhorses of your React applications. Use them in Form components for submissions and resets. Inside Dialog components, buttons handle confirmations and cancellations.
Combine buttons with DropdownMenu triggers for action menus. This open source pattern keeps interfaces clean while providing options. In Card components, buttons drive the primary actions—view details, add to cart, whatever moves users forward.
For navigation, use asChild
with your framework's Link component. Your JavaScript button looks like a button but navigates like a link. Best of both worlds.
Questions you might have
CLAUDE AI GUIDE: Creating Button Components
This section provides a complete step-by-step process for creating custom button components in the shadcn.io monorepo. Follow this guide exactly when given any button code to transform into a proper shadcn component package.
Complete Creation Process
Step 1: Create Package Structure
Create the package directory and files:
mkdir -p /packages/[button-name]/
Required files:
/packages/[button-name]/index.tsx
- Main component/packages/[button-name]/package.json
- Package config/packages/[button-name]/tsconfig.json
- TypeScript config/packages/[button-name]/tailwind.config.js
- Only if custom animations needed
Step 2: Package Configuration Template
package.json:
{
"name": "@repo/[button-name]",
"description": "[Brief component description]",
"version": "0.0.0",
"private": true,
"dependencies": {
"@repo/shadcn-ui": "workspace:*",
"react": "^19.1.0",
"react-dom": "^19.1.0"
},
"devDependencies": {
"@repo/typescript-config": "workspace:*",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"typescript": "^5.8.3"
}
}
tsconfig.json:
{
"extends": "@repo/typescript-config/nextjs.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@repo/*": ["../*"],
"@/components/*": ["../shadcn-ui/components/*"],
"@/lib/*": ["../shadcn-ui/lib/*"]
}
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
Step 3: Component Implementation Pattern
index.tsx template:
'use client';
import React from 'react';
import { cn } from '@repo/shadcn-ui/lib/utils';
export interface [ComponentName]Props
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
// Add specific props here
}
export const [ComponentName] = React.forwardRef<
HTMLButtonElement,
[ComponentName]Props
>(({
// Props with defaults
className,
style,
...props
}, ref) => {
return (
<button
ref={ref}
className={cn(
"base-classes-here",
className
)}
style={style}
{...props}
>
{/* Component content */}
</button>
);
});
[ComponentName].displayName = "[ComponentName]";
Critical Rules for Component Implementation:
- Always use
'use client'
directive - Use forwardRef pattern with proper types
- Include
className
andstyle
props for customization - Use
cn()
utility from shadcn-ui for className merging - Prefer inline styles over complex Tailwind arbitrary values for critical styling
- Use theme-aware colors (avoid hardcoded white/black)
- Keep component focused - only essential props, no overengineering
Step 4: Add to Documentation App
Add dependency to /apps/docs/package.json
in alphabetical order:
"@repo/[button-name]": "workspace:*",
Step 5: Create Example File
Create /apps/docs/examples/button/[button-name].tsx
:
import { [ComponentName] } from "@repo/[button-name]"
export default function [ExampleName]() {
return (
<div className="w-full p-6 flex justify-center">
<[ComponentName] />
</div>
)
}
Step 6: MDX Documentation Structure
Create /apps/docs/content/button/[button-name].mdx
following this EXACT template:
---
title: React [Button Name] Button
description: [Concise description with primary functionality]. [Unique selling point] with React, Next.js, TypeScript, and shadcn/ui integration.
icon: [LucideIconName]
component: true
---
<PoweredBy
packages={[
{ name: "React", url: "https://react.dev" },
{ name: "[Key Technology]", url: "https://tech-url.com" },
]}
/>
<Callout title="[Context-specific callout title]?">
[Join our Discord community](https://discord.com/invite/Z9NVtNE7bj) for help
from other developers.
</Callout>
<br />
[ENGAGING INTRODUCTION PARAGRAPH]
Use conversational tone. Start with a relatable scenario or problem. Explain why this button is different from boring alternatives. Use specific examples and developer pain points.
### [Descriptive action title]
[Brief explanation of the main feature]:
<Preview path="button/[button-name]" />
Built for React applications with TypeScript and Next.js. [Technical implementation details]. [Performance characteristics]. [Integration benefits with shadcn/ui].
## Installation
<Installer packageName="[button-name]" />
## Why [problem this solves]
[2-3 paragraphs explaining the user experience problem this button solves. Use conversational tone, specific examples, and relate to real development scenarios. Mention technical implementation benefits.]
## Features
- **[Core functionality]** with [technical implementation detail]
- **[Key feature 2]** using [specific technology or approach]
- **[Performance aspect]** with [optimization detail]
- **TypeScript support** with complete interface definitions
- **shadcn/ui integration** using design tokens and utilities
- **[Additional feature]** for [practical benefit]
## Examples (ONLY if you have truly different variants)
### [Variant Name]
<Preview path="button/[button-name]-[variant]" />
[Brief explanation of what makes this variant different]
## API Reference
### [ComponentName]
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `prop1` | `Type` | `"default"` | Clear description |
| `prop2` | `Type` | **required** | Required prop description |
| `className` | `string` | - | Additional CSS classes |
### [Additional sections if needed]
- Color variants, animation options, etc.
## Common gotchas
**[Issue 1]**: [Clear explanation and solution]
**[Issue 2]**: [Clear explanation and solution]
## You might also like
<Cards>
<Card
href="/button/[related-button]"
title="[Related Button]"
description="[Brief description]"
/>
</Cards>
## Questions developers actually ask
<Accordions type="single">
<Accordion id="question-id" title="[Practical question]?">
[Direct, helpful answer with code examples if needed]
</Accordion>
<Accordion id="question-id-2" title="[Another common question]?">
[Direct, helpful answer]
</Accordion>
</Accordions>
Critical Writing Guidelines
Tone & Voice
- Conversational, not formal - Write like talking to a fellow developer
- Problem-first approach - Start with pain points developers face
- Specific examples - "47 different button styles" not "many button styles"
- Avoid marketing fluff - No "revolutionary" or "cutting-edge"
- Developer-focused - Technical details, implementation notes, gotchas
Content Requirements
- Engaging intro - Hook with relatable scenario, not dry description
- Technical depth - Explain implementation, not just usage
- Real problems - Address actual developer pain points
- SEO keywords naturally integrated: react, nextjs, shadcn, typescript, tailwind, component, open source, free
- Practical examples - Working code, not abstract concepts
Structure Rules
- Never duplicate previews - Main preview at top is enough for basic usage
- Examples section only for different variants - Don't repeat the same thing
- API Reference must match actual component - Check props interface carefully
- Questions should be practical - What developers actually ask, not theoretical
Validation Checklist
- Component name matches throughout (PascalCase)
- Props table matches actual component interface
- Default values are accurate
- Preview path exists:
/apps/docs/examples/button/[name].tsx
- Package dependency added to docs package.json
- Installation uses
<Installer packageName="[name]" />
- Conversational tone throughout
- SEO keywords naturally integrated
- Technical implementation details included
- Common gotchas section addresses real issues
File Locations Summary
- Package:
/packages/[button-name]/
- Example:
/apps/docs/examples/button/[button-name].tsx
- MDX:
/apps/docs/content/button/[button-name].mdx
- Dependency:
/apps/docs/package.json
Registry Integration
The registry system automatically:
- Transforms imports for user installations
- Extracts dependencies from package.json
- Generates installation JSON endpoint
- Handles Tailwind config parsing (if present)
- Provides
npx shadcn add [button-name]
functionality
Follow this guide exactly for consistent, high-quality button component creation that integrates seamlessly with the shadcn.io ecosystem.
Shadcn Breadcrumb
React breadcrumb component for navigating complex hierarchies with dropdown support. Built with TypeScript and Tailwind CSS for Next.js applications.
Shadcn Calendar
React calendar component for date picking with ranges and keyboard navigation. Built with TypeScript and Tailwind CSS for Next.js using React DayPicker.