Componentform0.87 KB gzipZero dependencies
Button
Animated button with hover feedback and crisp focus.
Preview
Live Preview
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add buttonOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { Button } from "@/components/ui/button";
<Button>Admit one</Button>
<Button variant="outline" size="lg">Outline</Button>Usage guidance
Use Button when a ticket stub surface needs Animated button with hover feedback and crisp focus. Keep props minimal and prefer composition with sibling stubs.
Avoid Button for long form flows or dense data grids where a dedicated layout block fits better.
Source code
button.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
type Variant = "default" | "secondary" | "outline" | "ghost" | "link";
type Size = "default" | "sm" | "lg" | "icon";
export type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
variant?: Variant;
size?: Size;
/** Dual-mode: false renders instantly with no motion. Default true. */
animated?: boolean;
};
const variants: Record<Variant, string> = {
default: "border-2 border-dashed border-foreground bg-card text-foreground hover:border-solid hover:bg-primary hover:text-primary-foreground",
secondary: "border border-border bg-secondary text-secondary-foreground hover:bg-secondary/70",
outline: "border border-foreground bg-transparent hover:bg-secondary",
ghost: "hover:bg-secondary",
link: "text-accent-strong underline-offset-4 hover:underline",
};
const sizes: Record<Size, string> = {
default: "h-9 px-4 text-[13px]",
sm: "h-8 px-3 text-xs",
lg: "h-11 px-7 text-sm",
icon: "size-9",
};
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = "default", size = "default", animated = true, ...props }, ref) => (
<button
ref={ref}
className={cn(
"inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md font-mono uppercase tracking-[0.15em] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 disabled:transition-none [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
animated
? "transition-all duration-150 hover:scale-[1.02] active:scale-[0.97] motion-reduce:transition-none motion-reduce:hover:scale-100 motion-reduce:active:scale-100"
: "transition-none",
variants[variant],
sizes[size],
className
)}
{...props}
/>
)
);
Button.displayName = "Button";
export { Button };
Props
| Prop | Type | Description |
|---|---|---|
| variant | "default" | "secondary" | "outline" | "ghost" | "link" | Visual style. |
| size | "default" | "sm" | "lg" | "icon" | Size of the button. |
Pairs well with
Button GroupJoins buttons with rounded outer corners, internal separators, and sliding hover highlight.Loading ButtonButton with loading spinner swap, width locking to avoid jumps, and a brief success check-mark stamp.Split ButtonDual-action button with primary click trigger and dropdown secondary actions.Input GroupInput with prefix icon slot, suffix slot, and inner action button; dashed focus ring and animated underline sweep.