BackButton
components

Button

Versatile button component with multiple variants and sizes.

components/ui/button.tsx
import React from "react"

const classes = {
	base: "cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
	variant: {
		default: "bg-primary text-primary-foreground hover:bg-primary/90",
		destructive:
			"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
		outline: "border shadow-xs hover:text-accent-foreground hover:bg-accent dark:border-input dark:hover:bg-input/50",
		secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
		ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
		link: "text-primary underline-offset-4 hover:underline",
		transparent: "text-muted-foreground hover:text-foreground",
	},
	size: {
		default: "h-9 px-4 py-2",
		lg: "h-10 px-6",
		sm: "h-8 gap-1.5! px-3",
		xs: "h-6 gap-1.5! px-2 text-xs [&_svg:not([class*='size-'])]:size-3!",
		icon: "size-9",
		"icon-lg": "size-10 gap-1.5!",
		"icon-sm": "size-8 gap-1.5!",
		"icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3! gap-1!",
	},
}

export type ButtonVariant = keyof typeof classes.variant
export type ButtonSize = keyof typeof classes.size
export interface ButtonProps extends React.ComponentProps<"button"> {
	variant?: ButtonVariant
	size?: ButtonSize
	className?: string
}

export function buttonVariants({
	variant = "default",
	size = "default",
	className,
}: Pick<ButtonProps, "variant" | "size" | "className"> | undefined = {}) {
	return [classes.base, classes.variant[variant], classes.size[size], className].filter(Boolean).join(" ")
}

export function Button({ className, variant = "default", size = "default", ...props }: ButtonProps) {
	return (
		<button
			type="button"
			data-variant={variant}
			data-size={size}
			className={buttonVariants({ variant, size, className })}
			{...props}
		/>
	)
}
components/examples/button.tsx
import { Button } from "@/components/ui/button"

export function ButtonExample() {
	return <Button>Button</Button>
	// return <a className={buttonVariants({ variant: "link", size: "sm", className: "ml-2" })}>Button</a>
}