Button
Displays a button or a component that looks like a button.
Made by shadcnInstallation
Usage
The Button component supports multiple variants and sizes to fit different use cases in your application:
import { Button } from "@/components/redpanda-ui/button"
// Basic usage
<Button>Click me</Button>
// With variants
<Button variant="outline">Outline Button</Button>
<Button variant="destructive">Delete</Button>
<Button variant="ghost">Ghost Button</Button>
// With sizes
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
<Button size="icon">
<Plus className="h-4 w-4" />
</Button>
// Loading state
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Loading...
</Button>
// As a link wrapper
<Button asChild>
<Link href="/dashboard">Go to Dashboard</Link>
</Button>Composing Buttons
When designing interfaces with multiple buttons, visual hierarchy and consistency are essential. Follow these principles to create clear, intuitive button compositions:
The One Filled Button Rule
Use a singular filled button per screen or context. This filled button represents the primary action you want users to take—whether that's submitting a form, progressing through a flow, or completing a task. Multiple filled buttons create visual competition and dilute the primary action's importance.
Button Hierarchy
Buttons follow a clear visual hierarchy that communicates priority:
- Filled buttons (default, destructive) - Primary actions, highest emphasis
- Outline buttons (secondary-outline, destructive-outline) - Secondary actions, medium emphasis
- Ghost buttons (secondary-ghost, ghost) - Tertiary actions, lowest emphasis
Outline buttons are your workhorse—use them frequently for secondary actions. Their white background and border make them more prominent and user-friendly than ghost buttons, while still clearly secondary to filled buttons. Ghost buttons should be reserved for tertiary actions that shouldn't dominate the interface.
CRUD Action Patterns
When designing create, read, update, and delete operations, maintain consistency across your interface:
- Create actions - Use the default (filled) variant
- Edit/Update actions - Use secondary-outline variant
- Delete actions - Use destructive-outline variant
- Confirm delete - Use destructive (filled) variant in confirmation dialogs
This pattern creates a consistent visual language: filled buttons move forward with creation or confirmation, outline buttons for modification actions, and destructive variants clearly signal data removal.
Form and Multi-Step Flow Patterns
Forms, wizards, and multi-step processes require careful button placement to guide users through the experience:
- Submit/Next/Continue - Use default (filled) variant, only one per view
- Secondary actions (Save draft, Skip, etc.) - Use secondary-outline variant
- Back/Cancel - Use secondary-ghost variant
The filled button always represents forward progress. Back and cancel actions use ghost buttons since they're escape routes users shouldn't be encouraged to take.
Content Guidelines
Button content should be text OR an icon, never both. This maintains visual simplicity and clarity. When you need an icon with text, consider whether the icon is truly necessary—often the text alone is clearer. Icon-only buttons should be reserved for common, universally understood actions (close, search, menu) and should always include accessible labels.
When to use
Use this decision tree to determine which button variant is most appropriate for your context:
Variant Guidelines
Understanding each variant's purpose helps maintain consistent visual hierarchy across your interface:
-
Default - Your primary filled button. Use for forward-moving actions like "Submit", "Create", "Continue", and "Save". Only one per screen or context.
-
Secondary Outline - Your most frequently used secondary button. The white background and visible border provide clear emphasis while remaining visually secondary. Use for edit actions, secondary form actions, and any supporting operation that needs prominence.
-
Secondary Ghost - For tertiary actions that shouldn't dominate. Use sparingly for back/cancel actions in flows, or when you need a button-like interaction with minimal visual weight.
-
Destructive - The filled destructive variant for critical confirmations. Use exclusively in confirmation dialogs when users must confirm permanent data deletion.
-
Destructive Outline - For inline delete actions. The outline treatment makes destructive actions visible but not as visually dominant as filled buttons, appropriate for destructive operations in tables, cards, or lists.
-
Outline - A neutral outline button for general secondary actions that don't fit the secondary-outline or destructive patterns.
-
Ghost - Minimal tertiary actions in data-dense interfaces like tables, cards, or navigation. Use when you need interaction without adding visual weight.
-
Link - For actions that behave like navigation links. Use when the action feels more like "going somewhere" than "doing something".
-
Dashed - Specialized for "add new" or placeholder actions, commonly used in empty states or to add items to lists.
Link
You can use the buttonVariants helper to create a link that looks like a button.
import { buttonVariants } from "@/components/ui/button"<Link className={buttonVariants({ variant: "outline" })}>Click here</Link>Alternatively, you can set the asChild parameter and nest the link component from any router, including TanStack/React Router/Next.js/Remix paradigms.
<Button asChild>
<Link href="/login">Login</Link>
</Button>Anatomy
The Button component is built with composition in mind, using Radix UI's Slot primitive for flexibility:
Button Component Structure:
┌─────────────────────────────────────┐
│ Button Container │
│ ┌─────────────────────────────────┐ │
│ │ Slot/HTML button element │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ Content Area │ │ │
│ │ │ [Icon] [Text] [Icon] │ │ │
│ │ │ │ │ │
│ │ │ - Icons: auto-sized (4×4) │ │ │
│ │ │ - Text: inherits font style │ │ │
│ │ │ - Gap: 0.5rem between items │ │ │
│ │ └─────────────────────────────┘ │ │
│ └─────────────────────────────────┘ │
│ │
│ Properties: │
│ - variant: styling theme │
│ - size: dimensions & padding │
│ - asChild: render as child element │
│ - disabled: interaction state │
└─────────────────────────────────────┘Component Composition
- Base: Uses either
<button>element or Radix UI Slot for custom components - Styling: CSS classes via
class-variance-authorityfor consistent theming - Accessibility: Built-in focus states, disabled states, and ARIA support
- Icons: Automatically sized and positioned with proper spacing
- Content: Flexible content area supporting text, icons, or custom elements
Examples
Primary
Variants
Dashed
Link
Icon
With Icon
Loading
As Child
Router Integration
Credits
Built by malinskibeniamin. The source code is available on GitHub.