For the complete documentation index, see llms.txt. Markdown variants are available by appending .md to any URL or sending an Accept: text/markdown header. An agent skill is available at /.well-known/agent-skills/site-skill.md.
Home

Button

Triggers an action or navigates. Supports multiple visual variants and sizes.

import { Slot } from "@radix-ui/react-slot";
import { cva } from "class-variance-authority";
import type { VariantProps } from "class-variance-authority";
import * as React from "react";

import { cn } from "@/lib/utils";

const buttonVariants = cva(
  "inline-flex shrink-0 items-center justify-center gap-2 rounded-full text-sm font-semibold whitespace-nowrap backdrop-blur-md transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
  {
    defaultVariants: {
      size: "default",
      variant: "default",
    },
    variants: {
      size: {
        default: "h-9 px-5 py-2 has-[>svg]:px-4",
        icon: "size-9",
        "icon-lg": "size-10",
        "icon-sm": "size-8",
        "icon-xs": "size-6 rounded-full [&_svg:not([class*='size-'])]:size-3",
        lg: "h-10 rounded-full px-7 has-[>svg]:px-5",
        sm: "h-8 gap-1.5 rounded-full px-4 has-[>svg]:px-3",
        xs: "h-6 gap-1 rounded-full px-3 text-xs has-[>svg]:px-2 [&_svg:not([class*='size-'])]:size-3",
      },
      variant: {
        default:
          "bg-primary/80 text-primary-foreground border border-white/40 shadow-lg shadow-primary/40 hover:bg-primary hover:shadow-primary/50 dark:border-white/10",
        destructive:
          "bg-destructive/80 text-white border border-white/20 shadow-lg shadow-destructive/10 hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
        ghost:
          "hover:bg-accent/40 hover:text-accent-foreground hover:backdrop-blur-md dark:hover:bg-accent/20",
        link: "text-primary underline-offset-4 hover:underline backdrop-blur-none",
        outline:
          "border border-white/40 bg-white/10 shadow-md hover:bg-white/20 dark:border-white/10 dark:bg-white/5 dark:hover:bg-white/10",
        secondary:
          "bg-secondary/60 text-secondary-foreground border border-white/20 shadow-md hover:bg-secondary/75 dark:border-white/5",
      },
    },
  }
);

const Button = ({
  className,
  variant = "default",
  size = "default",
  asChild = false,
  ...props
}: React.ComponentProps<"button"> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean;
  }) => {
  const Comp = asChild ? Slot : "button";

  return (
    <Comp
      data-slot="button"
      data-variant={variant}
      data-size={size}
      className={cn(buttonVariants({ className, size, variant }))}
      {...props}
    />
  );
};

export { Button, buttonVariants };
export Button;

Variants

Six visual styles for different contexts and hierarchy levels.

Sizes

Four general sizes plus three icon-only sizes.

With Icon

Icons are sized automatically via [&_svg]:size-4.

Loading

Swap the icon for a spinner. Disable the button to prevent repeated submissions.

As Child

Use asChild to render the button styles on a different element.

Props

PropTypeDefaultDescription
variant"default" | "secondary" | "outline" | "ghost" | "destructive" | "link""default"Visual style
size"default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg""default"Size of the button
asChildbooleanfalseRenders children as the root element
classNamestring—Additional CSS classes

Usage

import { Button } from "@/components/ui/button";
import { MailIcon } from "lucide-react";
 
// Default
<Button>Click me</Button>
 
// Variant
<Button variant="outline">Cancel</Button>
 
// Size
<Button size="lg">Get started</Button>
 
// With icon
<Button><MailIcon />Send email</Button>

Specs

# Mint — Button Specs
 
## Component
 
- name: button
- file: registry/mint/button.tsx
- installs to: components/ui/button.tsx
- dependencies: class-variance-authority, radix-ui
 
## What is it
 
A multipurpose action trigger. Use it to submit forms, navigate, or initiate
operations. Prefer Button over a link when the action changes state or triggers
a process. Avoid using more than one "default" variant in the same visual area.
 
## Visual identity
 
Mint's fresh green palette. A medium green primary conveys energy and clarity.
Generous border radius (1.25rem) gives a light, airy, rounded feel, with soft
glassy borders throughout. A confident but approachable green found across
every accent.
 
## Design tokens
 
--primary: oklch(0.5 0.14 155) — medium green
--primary-foreground: oklch(1 0 0) — white
--secondary: oklch(0.95 0.04 155) — pale mint
--secondary-foreground: oklch(0.32 0.1 155)
--accent: oklch(0.92 0.05 155)
--accent-foreground: oklch(0.32 0.1 155)
--muted: oklch(0.96 0.02 155)
--muted-foreground: oklch(0.52 0.06 155) — soft green-grey
--destructive: oklch(0.55 0.25 15) — red
--border: oklch(0.88 0.04 155 / 60%) — soft glassy green-tinted border
--ring: oklch(0.5 0.14 155) — green focus ring
--radius: 1.25rem — generous, airy rounded
 
## Variants
 
- default → near-black fill. Primary CTA. High visual weight.
- secondary → light grey fill. Secondary action. Low visual weight.
- outline → transparent, grey border. Equal weight to secondary.
- ghost → no border, no fill. Tertiary action or toolbar button.
- destructive → red fill. Irreversible or dangerous actions only.
- link → text-only underline. Inline navigation or contextual actions.
 
## States
 
- hover: primary darkens slightly; outline/ghost shows tinted background
- focus: 3px ring in --ring colour (grey), offset 0
- disabled: opacity-50, pointer-events-none
- loading: Loader2Icon + animate-spin, always disable the button when loading
 
## Conventions
 
- One default variant per visual group maximum
- Pair default + outline for primary/secondary action pairs
- Pair default + ghost for toolbar actions
- Spacing between adjacent buttons: gap-2 (8px) minimum
- Icon-only buttons require aria-label
- SVG icons auto-size to 16px — do not override unless intentional

Installation

GIN Design Plugin
$ npx shadcn add https://gin-design.vercel.app/button