UI/UI
Button
Displays a button component with various styles and states.
<div className="flex gap-4 flex-wrap">
<Button>Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button variant="destructive">Destructive</Button>
</div>
Installation
Install following dependencies:
npm install @radix-ui/react-slot class-variance-authority
pnpm add @radix-ui/react-slot class-variance-authority
yarn add @radix-ui/react-slot class-variance-authority
bun add @radix-ui/react-slot class-variance-authority
Copy and paste the following code into your project.
"use client";
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-[var(--radius)] text-sm font-medium transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
default:
"bg-[hsl(var(--hu-primary))] text-[hsl(var(--hu-primary-foreground))] hover:bg-[hsl(var(--hu-primary))]/90 focus-visible:ring-[hsl(var(--hu-ring))]",
destructive:
"bg-[hsl(var(--hu-destructive))] text-[hsl(var(--hu-destructive-foreground))] hover:bg-[hsl(var(--hu-destructive))]/90 focus-visible:ring-[hsl(var(--hu-destructive))]",
outline:
"border border-[hsl(var(--hu-border))] text-[hsl(var(--hu-foreground))] hover:bg-[hsl(var(--hu-accent))] hover:text-[hsl(var(--hu-accent-foreground))] focus-visible:ring-[hsl(var(--hu-ring))]",
secondary:
"bg-[hsl(var(--hu-secondary))] text-[hsl(var(--hu-secondary-foreground))] hover:bg-[hsl(var(--hu-secondary))]/80 focus-visible:ring-[hsl(var(--hu-ring))]",
ghost:
"text-[hsl(var(--hu-foreground))] hover:bg-[hsl(var(--hu-accent))] hover:text-[hsl(var(--hu-accent-foreground))] focus-visible:ring-[hsl(var(--hu-ring))]",
link: "text-[hsl(var(--hu-secondary-foreground))] underline-offset-4 hover:underline focus-visible:ring-[hsl(var(--hu-ring))]",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 px-3 text-xs",
lg: "h-10 px-8",
xl: "h-12 px-10 text-base",
icon: "h-9 w-9",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
loading?: boolean;
leftIcon?: React.ReactNode;
rightIcon?: React.ReactNode;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
(
{
className,
variant,
size,
asChild = false,
loading = false,
leftIcon,
rightIcon,
children,
disabled,
...props
},
ref,
) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
disabled={disabled || loading}
{...props}
>
{loading && (
<svg
className="animate-spin -ml-1 mr-2 h-4 w-4"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
)}
{leftIcon && !loading && leftIcon}
{children}
{rightIcon && !loading && rightIcon}
</Comp>
);
},
);
Button.displayName = "Button";
export { Button, buttonVariants };
npx hextaui@latest add button
pnpm dlx hextaui@latest add button
yarn dlx hextaui@latest add button
bun x hextaui@latest add button
Usage
import { Button } from "@/components/ui/Button";
<Button>Click me</Button>
Examples
Default
<Button>Click me</Button>
Variants
<Button variant="default">Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button variant="destructive">Destructive</Button>
Sizes
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="xl">Extra Large</Button>
With Icons
<Button leftIcon={<Download />}>Download</Button>
<Button rightIcon={<ArrowRight />}>Continue</Button>
<Button variant="outline" leftIcon={<Heart />}>
Like
</Button>
<Button variant="secondary" rightIcon={<Settings />}>
Settings
</Button>
Icon Only
<Button variant="outline" size="icon">
<Settings />
</Button>
<Button variant="ghost" size="icon">
<Heart />
</Button>
<Button variant="destructive" size="icon">
<Trash2 />
</Button>
Loading State
<Button loading>Loading...</Button>
<Button variant="outline" loading>
Please wait
</Button>
<Button variant="secondary" loading disabled>
Processing
</Button>
Link
You can use the asChild
prop to make another component look like a button. Here's an example of a link that looks like a button.
import { Button } from "@/components/ui/Button";
import Link from "next/link";
export function LinkAsButton() {
return (
<Button asChild>
<Link href="/login">Login</Link>
</Button>
);
}
Props
Prop | Type | Default |
---|---|---|
className? | string | undefined |
disabled? | boolean | false |
rightIcon? | React.ReactNode | undefined |
leftIcon? | React.ReactNode | undefined |
loading? | boolean | false |
asChild? | boolean | false |
size? | "default" | "sm" | "lg" | "xl" | "icon" | "default" |
variant? | "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | "default" |
Edit on GitHub
Last updated on