Claude-skill-registry button-unification
Standardize button component heights, padding, and transitions across all variants. Ensures consistent appearance for default, outline, secondary, ghost, and link variants. Updates button.tsx with unified styles.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/button-unification" ~/.claude/skills/majiayu000-claude-skill-registry-button-unification && rm -rf "$T"
manifest:
skills/data/button-unification/SKILL.mdsource content
Button Unification
Standardize the button component for consistent heights, padding, and transitions across all variants.
Workflow
- Find Button Component - Locate
website/components/ui/button.tsx - Audit Current Styles - Review existing buttonVariants
- Standardize Heights - Unified height per size
- Standardize Padding - Consistent padding per size
- Standardize Typography - Same font size and weight and variant
- Unify Border-Radius - Same radius for all variants
- Unify Transitions - Same transition for all variants
- Background - Ensure background styles are consistent for each variant
- Icon Sizes - Standardize icon button dimensions for each size
- Text Color - Ensure text colors are consistent per variant
- Verify Consistency - Test all variant + size combinations
Size Specifications
Heights (Unified)
| Size | Height | Class |
|---|---|---|
| default | 36px | h-9 |
| sm | 32px | h-8 |
| lg | 40px | h-10 |
| icon | 36px | size-9 |
| icon-sm | 32px | size-8 |
| icon-lg | 40px | size-10 |
Padding (Unified)
| Size | Horizontal | With Icon | Gap |
|---|---|---|---|
| default | px-4 | has-[>svg]:px-3 | gap-2 |
| sm | px-3 | has-[>svg]:px-2.5 | gap-1.5 |
| lg | px-6 | has-[>svg]:px-4 | gap-2 |
Base Styles (All Variants)
All button variants share these base styles:
// Base class (applied to ALL variants) "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm text-white font-medium transition-all"
Key unified properties:
- Consistent border radiusrounded-md
- Consistent typographytext-sm font-medium text-white
- Consistent transitionstransition-all
(or gap-1.5 for sm) - Consistent spacinggap-2
Updated buttonVariants
See references/button-patterns.md for the complete CVA configuration.
const buttonVariants = cva( "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-white hover:bg-destructive/90", outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", }, size: { default: "h-9 px-4 py-2 has-[>svg]:px-3", sm: "h-8 gap-1.5 px-3 has-[>svg]:px-2.5", lg: "h-10 px-6 has-[>svg]:px-4", icon: "size-9", "icon-sm": "size-8", "icon-lg": "size-10", }, }, defaultVariants: { variant: "default", size: "default", }, } );
Visual Consistency Check
After updating, verify:
- Same Height - Buttons in a row align perfectly
- Same Padding - Text has consistent spacing
- Same Radius - Corners match across variants
- Same Transition - Hover effects are smooth and consistent
- Same Font - Text appears identical size
- Icon Sizes - Icon buttons have correct dimensions
Button with Next.js Link
When a button needs to navigate, use the
asChild prop with Next.js <Link>:
import Link from "next/link"; import { Button } from "@/components/ui/button"; // Correct pattern - Button wraps Link with asChild <Button asChild> <Link href="/login">Login</Link> </Button> <Button asChild variant="outline" size="sm"> <Link href="/contact">Contact</Link> </Button> <Button asChild variant="ghost" size="icon"> <Link href="/settings"> <Settings className="size-4" /> </Link> </Button>
Key points:
- Always use
prop when wrapping LinkasChild - Link is the child, Button provides styling
- Works with all variants and sizes
- Preserves Next.js client-side navigation
DO NOT do this:
// WRONG - Button onClick with router.push <Button onClick={() => router.push('/login')}>Login</Button> // WRONG - Link wrapping Button <Link href="/login"><Button>Login</Button></Link>
Testing
Test all variant + size combinations:
// All variants at same size should have identical height <div className="flex gap-2"> <Button variant="default">Default</Button> <Button variant="outline">Outline</Button> <Button variant="secondary">Secondary</Button> <Button variant="ghost">Ghost</Button> </div>
Checklist
- All sizes have unified heights (h-9, h-8, h-10)
- All sizes have unified padding (px-4, px-3, px-6)
- All variants use rounded-md
- All variants use transition-all
- All sizes use text-sm font-medium
- Icon sizes use square dimensions (size-9, size-8, size-10)
- Gap is consistent per size (gap-2, gap-1.5)
- Focus ring styles are consistent across variants
- Navigation buttons use
withasChild<Link>