Button
The button component
Basic Usage
import { Button } from "@repo/ui/components/button";
import { Info } from "lucide-react";
/* BASIC USAGE EXAMPLES */
export const Example1 = () => {
return (
<div className="flex flex-wrap items-center justify-center gap-4">
<Button>Default</Button>
<Button variant={"outline"}>Outline</Button>
<Button size={"icon"} variant={"outline"}>
<Info />
</Button>
</div>
);
};
Sizes
import { Button } from "@repo/ui/components/button";
import { BusIcon, Info, MenuSquareIcon } from "lucide-react";
export const Example2 = () => {
return (
<div>
<div className="flex flex-wrap items-center justify-center gap-4">
<Button size={"sm"} variant={"outline"}>
Small
</Button>
<Button size={"default"} variant={"outline"}>
Default
</Button>
<Button size={"lg"} variant={"outline"}>
Large
</Button>
</div>
<div className="mt-5 flex flex-wrap items-center justify-center gap-4">
<Button size={"icon-sm"} variant={"outline"}>
<Info />
</Button>
<Button size={"icon"} variant={"outline"}>
<MenuSquareIcon />
</Button>
<Button size={"icon-lg"} variant={"outline"}>
<BusIcon />
</Button>
</div>
</div>
);
};
Variants
import { Button } from "@repo/ui/components/button";
export const Example3 = () => {
return (
<div>
<div className="flex flex-wrap items-center justify-center gap-5 md:gap-4">
<Button> Default </Button>
<Button variant={"gradient"}> Gradient </Button>
<Button variant={"outline"}> Outline </Button>
<Button variant={"secondary"}> Secondary </Button>
<Button variant={"ghost"}> Ghost </Button>
<Button variant={"destructive"}> Destructive </Button>
<Button variant={"link"}> Link </Button>
</div>
<div className="mt-5 flex flex-wrap items-center justify-center gap-5 md:gap-4">
<Button variant={"adobe"}> Adobe </Button>
<Button variant={"instagram"}> Instagram </Button>
</div>
</div>
);
};
Component Code
"use client";
import { ReactNode, forwardRef } from "react";
import {
Button as AriaButton,
ButtonProps as AriaButtonProps,
ButtonContext as AriaButtonContext,
} from "react-aria-components";
import { tv, type VariantProps, cn } from "tailwind-variants";
export const buttonVariants = tv({
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-xl text-sm font-medium outline-none transition-transform duration-200 ease-in-out hover:scale-105 focus-visible:ring-[3px] active:scale-100 disabled:pointer-events-none disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
variants: {
variant: {
default:
"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90 focus-visible:ring-primary/20 dark:focus-visible:ring-primary/40",
gradient:
"text-primary-foreground shadow-xs hover:bg-primary/90 bg-linear-to-br from-indigo-600 to-purple-600 hover:from-purple-600 hover:to-indigo-600",
destructive:
"bg-destructive shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60 text-white",
outline:
"bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 border",
secondary:
"bg-secondary text-secondary-foreground shadow-xs 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",
adobe: "rounded-full bg-[#3B63FB] font-semibold text-white shadow-sm hover:bg-[#274dea] focus-visible:ring-1 focus-visible:ring-[#274dea]/40 focus-visible:ring-offset-0 active:bg-[#274dea]",
instagram:
"bg-linear-to-tr rounded-full from-[#F58529] via-[#DD2A7B] to-[#515BD4] font-semibold text-white shadow-sm hover:opacity-90 focus-visible:ring-2 focus-visible:ring-[#DD2A7B]/40 focus-visible:ring-offset-2 active:opacity-80",
},
size: {
default: "h-10 px-6 has-[>svg]:px-3",
sm: "h-9 gap-1.5 px-5 has-[>svg]:px-2.5",
lg: "h-12 px-7 has-[>svg]:px-4",
icon: "h-10 w-10",
"icon-sm": "h-9 w-9",
"icon-lg": "h-11 w-11",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
});
interface ButtonProps
extends Omit<AriaButtonProps, "children">,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
children: ReactNode;
}
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
const { variant, size, className, children, asChild, ...restProps } =
props;
const finalProps = {
...restProps,
ref,
className: cn(buttonVariants({ variant, size }), className),
children,
};
if (asChild) {
return (
<AriaButtonContext value={finalProps}>
{children}
</AriaButtonContext>
);
}
return <AriaButton {...finalProps}>{children}</AriaButton>;
},
);
Button.displayName = "Button";