MC Button
A clickable interactive element.
Overview
The mc-button is a core component of the MicroClub UI library. Built on the @base-ui/react button primitive, it combines world-class accessibility with MicroClub's signature styling via Tailwind CSS v4.
As a part of the MicroClub library, this component is designed for instant deployment into your codebase, giving you full ownership of its look and behavior.
Preview
import { McButton } from "../ui/mc-button";export default function McButtonDemo() { return <McButton>Button</McButton>;}Add to Your Project
Deploy the mc-button directly to your components/ui directory:
npx mcoli-ui@latest add mc-buttonManual Setup
If you prefer manual control:
npm install clsx tailwind-merge @base-ui/react class-variance-authority lucide-reactimport * as React from "react";import { Button as ButtonPrimitive } from "@base-ui/react/button";import { cva, type VariantProps } from "class-variance-authority";import { LinkIcon, Loader2 } from "lucide-react";import { cn } from "@/lib/utils";const buttonVariants = cva( "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding whitespace-nowrap transition-all outline-none select-none disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0", { variants: { variant: { primary: "bg-primary text-primary-foreground hover:bg-secondary-foreground hover:text-secondary active:bg-secondary-foreground active:text-secondary active:ring-4 active:ring-secondary disabled:bg-muted disabled:text-muted-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-accent hover:text-accent-foreground active:bg-accent active:text-accent-foreground active:ring-4 active:ring-secondary disabled:bg-muted disabled:text-muted-foreground", tertiary: "bg-primary-foreground text-primary hover:text-accent-foreground active:text-accent-foreground active:ring-4 active:ring-secondary disabled:bg-muted disabled:text-muted-foreground", link: "bg-transparent p-0 text-foreground underline hover:text-accent-foreground active:text-accent-foreground disabled:text-muted-foreground", }, size: { sm: "px-3.5 py-2 text-sm font-medium", md: "px-4 py-2.5 text-sm font-medium", lg: "px-[1.125rem] py-2.5 text-base font-medium", xl: "px-5 py-3 text-base font-medium", }, icon: { none: "", leading: "gap-2", trailing: "gap-2", dot: "gap-2", only: "", }, destructive: { true: "", false: "", }, }, compoundVariants: [ { variant: "link", className: "px-0 py-0", }, { icon: "only", size: "sm", className: "p-2", }, { icon: "only", size: "md", className: "p-2.5", }, { icon: "only", size: "lg", className: "p-3", }, { icon: "only", size: "xl", className: "p-3.5", }, // Destructive overrides { destructive: true, variant: "primary", className: "bg-destructive text-destructive-foreground hover:bg-destructive/90 active:bg-destructive/90 active:ring-4 active:ring-destructive/20", }, { destructive: true, variant: "secondary", className: "bg-destructive/10 text-destructive hover:bg-destructive/20 active:ring-4 active:ring-destructive/20", }, { destructive: true, variant: "tertiary", className: "text-destructive hover:bg-destructive/10 active:ring-4 active:ring-destructive/20", }, { destructive: true, variant: "link", className: "text-destructive hover:text-destructive/80 active:text-destructive/80", }, ], defaultVariants: { variant: "primary", size: "md", icon: "none", destructive: false, }, },);export interface McButtonProps extends Omit<ButtonPrimitive.Props, "icon">, Omit<VariantProps<typeof buttonVariants>, "icon"> { iconDefinition?: React.ReactNode; icon?: "none" | "leading" | "trailing" | "dot" | "only"; isLoading?: boolean;}function McButton({ className, variant = "primary", size, icon = "none", destructive, iconDefinition, isLoading, children, disabled, ...props}: McButtonProps) { const isLink = variant === "link"; const effectiveIcon = isLink && (icon === "leading" || icon === "trailing") && !iconDefinition ? ( <LinkIcon /> ) : ( iconDefinition ); return ( <ButtonPrimitive data-slot="button" disabled={disabled || isLoading} className={cn( buttonVariants({ variant, size, icon: icon === "none" ? "none" : icon, destructive, className, }), isLoading && "gap-2", )} {...props} > {isLoading ? ( <Loader2 className="size-4 animate-spin shrink-0" /> ) : ( <> {icon === "dot" && ( <span data-slot="dot" className="size-2.5 shrink-0 rounded-full bg-current" /> )} {icon === "leading" && effectiveIcon && ( <span data-slot="leading-icon" className="size-4 shrink-0 [&_svg]:size-full" > {effectiveIcon} </span> )} </> )} {icon !== "only" && children} {icon === "only" && !isLoading && effectiveIcon} {icon === "trailing" && !isLoading && effectiveIcon && ( <span data-slot="trailing-icon" className="size-4 shrink-0 [&_svg]:size-full" > {effectiveIcon} </span> )} </ButtonPrimitive> );}export { McButton, buttonVariants };Ensure your @/lib/utils or equivalent classname helper is correctly imported.
Usage
import { McButton } from "@/components/ui/mc-button"
export default function Example() {
return <McButton variant="primary">Click me</McButton>
}Examples
Variants
<McButton variant="primary">Primary</McButton>
<McButton variant="secondary">Secondary</McButton>
<McButton variant="tertiary">Tertiary</McButton>
<McButton variant="link">Link</McButton>Sizes
<McButton size="sm">Small</McButton>
<McButton size="md">Medium</McButton>
<McButton size="lg">Large</McButton>
<McButton size="xl">Extra Large</McButton>Icons Support
The mc-button features a unified icon system using the icon and iconDefinition props.
import { Mail, ArrowRight, Plus } from "lucide-react"
<McButton icon="leading" iconDefinition={<Mail />}>
Send Email
</McButton>
<McButton icon="trailing" iconDefinition={<ArrowRight />}>
Get Started
</McButton>
<McButton icon="dot">
Status Online
</McButton>
<McButton icon="only" iconDefinition={<Plus />} />States
Handle loading and destructive actions with dedicated boolean props.
<McButton isLoading>Processing...</McButton>
<McButton destructive variant="primary">
Delete Account
</McButton>Link Variant
The link variant automatically includes a LinkIcon when an icon mode is selected but no iconDefinition is provided.
<McButton variant="link" icon="leading">
View Documentation
</McButton>API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "primary" | "secondary" | "tertiary" | "link" | "primary" | The visual style of the button |
size | "sm" | "md" | "lg" | "xl" | "md" | The size of the button |
icon | "none" | "leading" | "trailing" | "dot" | "only" | "none" | The placement mode for icons |
iconDefinition | ReactNode | undefined | The icon to render (except for "dot" mode) |
destructive | boolean | false | Applies a destructive theme to the current variant |
isLoading | boolean | false | Shows a spinner and disables interactions |
render | ReactElement | ((props: HTMLProps) => ReactElement) | undefined | Polymorphic render prop from Base UI |
className | string | undefined | Additional CSS classes |
All other props from @base-ui/react/button are supported.