buttons
Button
A versatile, minimalist button component with support for multiple aesthetic variants, sizes, and states.
buttonvariantsprimarysecondaryoutlineghostinteractive
▶Preview
Select Color & Active Theming
All variants pair and style dynamically matching the “zinc” color family:
Sizes
Inactive States
🖲Usage
example-usage.tsx
import { Button } from "@/components/kanso/button"
export default function ButtonDemo() {
return (
<div className="flex gap-4">
<Button variant="primary">Primary</Button>
<Button variant="secondary" color="blue">Secondary Blue</Button>
<Button variant="outline">Outline</Button>
</div>
)
}↓Installation
1
Create folder & copy source
Create a folder named kanso inside your project's components directory (i.e. components/kanso/). Copy the source code shown in the next section, and paste it into a file named button.tsx inside it.
2
Required helper files
Ensure your project has the following helper files configured:
- →
lib/utils
<>Source Code
button.tsx
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
"inline-flex shrink-0 items-center justify-center rounded-lg 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-40 disabled:cursor-not-allowed active:scale-[0.98]",
{
variants: {
variant: {
primary: "shadow-sm",
secondary: "shadow-2xs",
outline: "border bg-transparent shadow-3xs",
ghost: "",
link: "underline-offset-4 hover:underline p-0 h-auto rounded-none active:scale-100",
},
size: {
default: "h-9.5 px-4 py-2",
sm: "h-8.5 rounded-md px-3 text-xs",
lg: "h-11 rounded-lg px-6 text-base",
icon: "size-9.5",
},
color: {
zinc: "",
blue: "",
emerald: "",
violet: "",
amber: "",
rose: "",
},
},
compoundVariants: [
// Zinc
{
color: "zinc",
variant: "primary",
className: "bg-zinc-950 text-zinc-50 hover:bg-zinc-800 dark:bg-zinc-50 dark:text-zinc-950 dark:hover:bg-zinc-200 focus-visible:ring-zinc-400",
},
{
color: "zinc",
variant: "secondary",
className: "bg-zinc-100 text-zinc-900 hover:bg-zinc-200/80 dark:bg-zinc-900 dark:text-zinc-50 dark:hover:bg-zinc-800/80 focus-visible:ring-zinc-400",
},
{
color: "zinc",
variant: "outline",
className: "border-zinc-200 text-zinc-900 hover:bg-zinc-50 dark:border-zinc-800 dark:text-zinc-100 dark:hover:bg-zinc-900/60 focus-visible:ring-zinc-400",
},
{
color: "zinc",
variant: "ghost",
className: "hover:bg-zinc-100 hover:text-zinc-900 dark:hover:bg-zinc-900 dark:hover:text-zinc-50 focus-visible:ring-zinc-400",
},
{
color: "zinc",
variant: "link",
className: "text-zinc-900 dark:text-zinc-50 focus-visible:ring-zinc-400",
},
// Blue
{
color: "blue",
variant: "primary",
className: "bg-blue-600 text-white hover:bg-blue-500 dark:bg-blue-500 dark:hover:bg-blue-400 focus-visible:ring-blue-400",
},
{
color: "blue",
variant: "secondary",
className: "bg-blue-50 text-blue-900 hover:bg-blue-100 dark:bg-blue-950/40 dark:text-blue-200 dark:hover:bg-blue-950/60 focus-visible:ring-blue-400",
},
{
color: "blue",
variant: "outline",
className: "border-blue-200 text-blue-600 hover:bg-blue-50/50 dark:border-blue-900/60 dark:text-blue-400 dark:hover:bg-blue-950/20 focus-visible:ring-blue-400",
},
{
color: "blue",
variant: "ghost",
className: "text-blue-600 hover:bg-blue-50 dark:text-blue-400 dark:hover:bg-blue-950/30 focus-visible:ring-blue-400",
},
{
color: "blue",
variant: "link",
className: "text-blue-600 dark:text-blue-400 focus-visible:ring-blue-400",
},
// Emerald
{
color: "emerald",
variant: "primary",
className: "bg-emerald-600 text-white hover:bg-emerald-500 dark:bg-emerald-500 dark:hover:bg-emerald-400 focus-visible:ring-emerald-400",
},
{
color: "emerald",
variant: "secondary",
className: "bg-emerald-50 text-emerald-900 hover:bg-emerald-100 dark:bg-emerald-950/40 dark:text-emerald-200 dark:hover:bg-emerald-950/60 focus-visible:ring-emerald-400",
},
{
color: "emerald",
variant: "outline",
className: "border-emerald-200 text-emerald-600 hover:bg-emerald-50/50 dark:border-emerald-900/60 dark:text-emerald-400 dark:hover:bg-emerald-950/20 focus-visible:ring-emerald-400",
},
{
color: "emerald",
variant: "ghost",
className: "text-emerald-600 hover:bg-emerald-50 dark:text-emerald-400 dark:hover:bg-emerald-950/30 focus-visible:ring-emerald-400",
},
{
color: "emerald",
variant: "link",
className: "text-emerald-600 dark:text-emerald-400 focus-visible:ring-emerald-400",
},
// Violet
{
color: "violet",
variant: "primary",
className: "bg-violet-600 text-white hover:bg-violet-500 dark:bg-violet-500 dark:hover:bg-violet-400 focus-visible:ring-violet-400",
},
{
color: "violet",
variant: "secondary",
className: "bg-violet-50 text-violet-900 hover:bg-violet-100 dark:bg-violet-950/40 dark:text-violet-200 dark:hover:bg-violet-950/60 focus-visible:ring-violet-400",
},
{
color: "violet",
variant: "outline",
className: "border-violet-200 text-violet-600 hover:bg-violet-50/50 dark:border-violet-900/60 dark:text-violet-400 dark:hover:bg-violet-950/20 focus-visible:ring-violet-400",
},
{
color: "violet",
variant: "ghost",
className: "text-violet-600 hover:bg-violet-50 dark:text-violet-400 dark:hover:bg-violet-950/30 focus-visible:ring-violet-400",
},
{
color: "violet",
variant: "link",
className: "text-violet-600 dark:text-violet-400 focus-visible:ring-violet-400",
},
// Amber
{
color: "amber",
variant: "primary",
className: "bg-amber-600 text-white hover:bg-amber-500 dark:bg-amber-500 dark:text-zinc-950 dark:hover:bg-amber-400 focus-visible:ring-amber-400",
},
{
color: "amber",
variant: "secondary",
className: "bg-amber-50 text-amber-900 hover:bg-amber-100 dark:bg-amber-950/40 dark:text-amber-200 dark:hover:bg-amber-950/60 focus-visible:ring-amber-400",
},
{
color: "amber",
variant: "outline",
className: "border-amber-200 text-amber-600 hover:bg-amber-50/50 dark:border-amber-900/60 dark:text-amber-400 dark:hover:bg-amber-950/20 focus-visible:ring-amber-400",
},
{
color: "amber",
variant: "ghost",
className: "text-amber-600 hover:bg-amber-50 dark:text-amber-400 dark:hover:bg-amber-950/30 focus-visible:ring-amber-400",
},
{
color: "amber",
variant: "link",
className: "text-amber-600 dark:text-amber-400 focus-visible:ring-amber-400",
},
// Rose
{
color: "rose",
variant: "primary",
className: "bg-rose-600 text-white hover:bg-rose-500 dark:bg-rose-500 dark:hover:bg-rose-400 focus-visible:ring-rose-400",
},
{
color: "rose",
variant: "secondary",
className: "bg-rose-50 text-rose-900 hover:bg-rose-100 dark:bg-rose-950/40 dark:text-rose-200 dark:hover:bg-rose-950/60 focus-visible:ring-rose-400",
},
{
color: "rose",
variant: "outline",
className: "border-rose-200 text-rose-600 hover:bg-rose-50/50 dark:border-rose-900/60 dark:text-rose-400 dark:hover:bg-rose-950/20 focus-visible:ring-rose-400",
},
{
color: "rose",
variant: "ghost",
className: "text-rose-600 hover:bg-rose-50 dark:text-rose-400 dark:hover:bg-rose-950/30 focus-visible:ring-rose-400",
},
{
color: "rose",
variant: "link",
className: "text-rose-600 dark:text-rose-400 focus-visible:ring-rose-400",
},
],
defaultVariants: {
variant: "primary",
size: "default",
color: "zinc",
},
}
)
interface ButtonProps
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "color">,
VariantProps<typeof buttonVariants> {
/** Inactive state rendering the button disabled */
inactive?: boolean
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, color, inactive, ...props }, ref) => {
return (
<button
ref={ref}
disabled={inactive}
className={cn(buttonVariants({ variant, size, color, className }))}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button, buttonVariants }
export type { ButtonProps }
≡Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "primary" | "secondary" | "outline" | "ghost" | "link" | "primary" | The visual style variant of the button. |
color | "zinc" | "blue" | "emerald" | "violet" | "amber" | "rose" | "zinc" | The color theme of the button across its variants. |
size | "default" | "sm" | "lg" | "icon" | "default" | The height and padding scale of the button. |
inactive | boolean | false | When true, disables interactions and styles the button as inactive. |
childrenrequired | React.ReactNode | — | The content (text, label, or icons) inside the button. |
className | string | — | Additional CSS classes to apply custom overrides. |