ComponentsGeneral
Button
A versatile button component with multiple variants and sizes. Built with CVA and CSS Modules — copy it into your project and own it completely.
npx visor add buttonVariants
Sizes
Disabled State
Installation
npx visor add buttonThis copies two files into your project:
components/ui/button/button.tsx— the componentcomponents/ui/button/button.module.css— the styles
Usage
import { Button } from '@/components/ui/button/button';
export default function Example() {
return <Button>Click me</Button>;
}API Reference
ButtonProps
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'default' | Visual style variant of the button. |
size | 'sm' | 'md' | 'lg' | 'md' | Size of the button, affecting height and padding. |
asChild | boolean | false | Merge props onto the immediate child element instead of rendering a <button>. |
disabled | boolean | false | Disables the button and applies reduced-opacity styling. |
className | string | — | Additional CSS class names to merge onto the element. |
onClick | React.MouseEventHandler<HTMLButtonElement> | — | Click event handler. |
...props | React.ButtonHTMLAttributes<HTMLButtonElement> | — | All standard HTML button attributes are forwarded. |
The component also accepts all standard <button> HTML attributes.
Source Files
After running npx visor add button, you'll have:
button.tsx
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import styles from "./button.module.css";
const buttonVariants = cva(styles.base, {
variants: {
variant: {
default: styles.variantDefault,
secondary: styles.variantSecondary,
outline: styles.variantOutline,
ghost: styles.variantGhost,
destructive: styles.variantDestructive,
},
size: {
sm: styles.sizeSm,
md: styles.sizeMd,
lg: styles.sizeLg,
},
},
defaultVariants: {
variant: "default",
size: "md",
},
});
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size }), className)}
ref={ref}
{...props}
/>
);
}
);
Button.displayName = "Button";
export { Button, buttonVariants };button.module.css
All styles use CSS custom properties from @loworbitstudio/visor-core, so the button automatically adapts to your active theme.
Customization
After copying the component, you own it completely. Common customizations:
// Add a loading state
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, loading, children, ...props }, ref) => {
return (
<button
className={cn(buttonVariants({ variant, size }), className)}
disabled={loading || props.disabled}
ref={ref}
{...props}
>
{loading ? <Spinner size={16} /> : children}
</button>
);
}
);