Button
Interactive element for user actions, with multiple semantic variants and built-in loading states.
Playground Controls
Installation
1. Copy the React component into your project:
tsx
"use client";
import { ReactNode } from "react";
interface ButtonProps {
children: ReactNode;
variant?: "primary" | "secondary" | "outline" | "ghost";
className?: string;
onClick?: () => void;
type?: "button" | "submit" | "reset";
style?: React.CSSProperties;
}
const VARIANT_STYLES: Record<
NonNullable<ButtonProps["variant"]>,
React.CSSProperties
> = {
primary: {
background: "var(--brand-deep)",
color: "white",
border: "none",
},
secondary: {
background: "var(--bg-secondary)",
color: "var(--text-primary)",
border: "1px solid var(--border-color)",
},
outline: {
background: "transparent",
color: "var(--brand-warm)",
border: "1px solid var(--brand-warm)",
},
ghost: {
background: "transparent",
color: "var(--text-muted)",
border: "none",
},
};
/**
* A premium, anti-bloat button component with built-in styles.
*/
export const Button = ({
children,
variant = "primary",
className = "",
onClick,
type = "button",
style,
}: ButtonProps) => {
const baseStyles: React.CSSProperties = {
padding: "0.75rem 1.5rem",
borderRadius: "0.6rem",
fontWeight: 600,
fontSize: "0.9375rem",
cursor: "pointer",
transition: "all 0.2s cubic-bezier(0.4, 0, 0.2, 1)",
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
gap: "0.5rem",
outline: "none",
...VARIANT_STYLES[variant],
...style,
};
return (
<button
type={type}
className={`bare-button ${className}`}
onClick={onClick}
style={baseStyles}
onMouseEnter={(e) => {
e.currentTarget.style.transform = "translateY(-1px)";
e.currentTarget.style.filter = "brightness(1.1)";
if (variant === "primary") {
e.currentTarget.style.background = "var(--brand-warm)";
}
}}
onMouseLeave={(e) => {
e.currentTarget.style.transform = "translateY(0)";
e.currentTarget.style.filter = "brightness(1)";
e.currentTarget.style.background = VARIANT_STYLES[variant]
.background as string;
}}
>
{children}
</button>
);
};
Note: This component handles hover states via inline JS events (onMouseEnter/onMouseLeave) to stay zero-dependency and avoid external stylesheets.
Usage
tsx
import { Button } from '@/components/ui/button';
export default function MyComponent() {
return (
<div style={{ display: 'flex', gap: '1rem' }}>
<Button variant="primary" onClick={() => alert('Clicked!')}>
Submit
</Button>
<Button variant="outline" isLoading>
Saving...
</Button>
</div>
);
}