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 };