button

A button component that can be used as a child of other components. It supports different styles and sizes.

-> Variants-> Installation-> More Examples

Features

Variants

Different button variants.

Show Code
<Button>Share</Button>
<Button subtle>Settings</Button>
<Button outline>Settings</Button>
<Button primary>Log In</Button>
<Button destructive>Share</Button>
<Button destructive subtle>Settings</Button>
<Button destructive outline>Settings</Button>
<Button destructive primary>Log In</Button>

Disabled

Disabled button states.

Show Code
<>
<Button disabled>Share</Button>
<Button outline disabled>Settings</Button>
<Button primary disabled>
<MingcuteLoading3Fill className="animate-spin" />
Saving...
</Button>
</>

Icon

Button with icons. Icons are mostly retrieved from icones.js.org

Show Code
<>
<Button icon>
<CommentIcon />
</Button>
<Button outline>
<CommentIcon />
Comment
</Button>
<Button primary>
Next
<LucideArrowRight />
</Button>
</>

Sizes

Button sizes.

Show Code
<div className="flex flex-row @xs/previewcard:flex-col gap-2">
<div className="flex flex-col @xs/previewcard:flex-row gap-2 items-center">
<Button primary xs>
Send
</Button>
<Button primary sm>
Send
</Button>
<Button primary>
Send
</Button>
<Button primary lg>
Send
</Button>
<Button primary xl>
Send
</Button>
</div>
<div className="flex flex-col @xs/previewcard:flex-row gap-2 items-center">
<Button icon primary xs>
<LucideArrowRight />
</Button>
<Button icon primary sm>
<LucideArrowRight />
</Button>
<Button primary>
Send
<LucideArrowRight />
</Button>
<Button primary lg>
Send
<LucideArrowRight />
</Button>
<Button primary xl>
Send
<LucideArrowRight />
</Button>
</div>
</div>

Bare

Button without padding.

Show Code
<div className="flex flex-col">
<Button bare>
<LucideArrowLeft />
Back to Posts
</Button>
<Button bare>
<LucideArrowLeft />
Settings
</Button>
</div>

Source Code

Dependencies

npm i @radix-ui/react-slot lazy-cn

Source

import { Slot } from "@radix-ui/react-slot";
import { cn } from "lazy-cn";
import type { ComponentProps, SVGProps } from "react";
export function Button({
className,
asChild,
primary, outline, subtle, bare,
destructive,
icon,
round,
xs, sm, lg, xl,
...props
}: ComponentProps<"button"> & {
asChild?: boolean,
primary?: boolean, outline?: boolean, subtle?: boolean, bare?: boolean,
destructive?: boolean,
icon?: boolean,
disabled?: boolean,
xs?: boolean, sm?: boolean, lg?: boolean, xl?: boolean,
round?: boolean,
}) {
const Comp = asChild ? Slot : "button";
return (
<Comp {...props} className={cn(
"flex items-center gap-2 box-border",
"h-8.5 px-4",
icon && "px-3",
"rounded-md",
"text-sm leading-none font-medium text-nowrap",
"cursor-pointer select-none",
"transition-[translate] active:translate-y-0.5",
"hover:bg-foreground/5",
"focus-visible:outline-4",
"focus-visible:outline-focus",
"[&_svg]:size-4 [&_svg]:shrink-0",
round && "rounded-full",
xs && ["h-7 text-xs px-2", icon && "w-7 p-0 justify-center"],
sm && ["h-8 px-3", icon && "w-8 p-0 justify-center"],
lg && ["h-10 [&_svg]:size-4.5", icon && "w-10 p-0 justify-center"],
xl && ["h-10 text-base px-5 [&_svg]:size-5 tracking-tight rounded-lg", icon && "w-11 p-0 justify-center"],
primary && [
"text-background",
"bg-primary hover:bg-primary-hover",
"shadow-sm"
],
subtle && "bg-primary/5 hover:bg-primary/10",
outline && "border border-border shadow-xs active:bg-foreground/8",
bare && "p-0 hover:bg-transparent text-foreground/75 hover:text-foreground",
destructive && [
"text-destructive",
"hover:bg-destructive/5",
"focus-visible:outline-destructive-focus",
primary && [
"text-background",
"bg-destructive hover:bg-destructive-hover",
],
subtle && "bg-destructive/5 shadow-xs",
outline && "border-destructive-border",
],
props.disabled && [
"cursor-not-allowed",
"opacity-50",
"pointer-events-none",
],
className,
)} />
)
}

Tokens

@theme {
--color-destructive-border: --alpha(var(--color-destructive) / 0.25)
--color-destructive-hover: color-mix(in oklab, var(--color-background) 8%, var(--color-destructive))
--color-destructive-focus: --alpha(var(--color-destructive) / 0.25)
--color-destructive: var(--color-red-600)
--color-border: color-mix(in hsl, var(--color-foreground) 20%, var(--color-background))
--color-primary-hover: color-mix(in oklab, var(--color-background) 8%, var(--color-primary))
--color-primary: var(--color-neutral-700)
--color-background: #fff
--color-muted: color-mix(in hsl, var(--color-foreground) 50%, var(--color-background))
--color-focus: color-mix(in oklab, var(--color-muted) 25%, transparent)
--color-foreground: var(--color-neutral-700)
}

More Examples

React 19 Form

A button that works under React 19 <form>.

Show Code
import { Button } from "../components/button"
import { useFormStatus } from "react-dom"
import { cn } from "lazy-cn"
export function SubmitButtonWithIcon({ className, ...props }:
ComponentProps<typeof Button>
) {
const { pending } = useFormStatus()
return (
<Button
type="submit"
disabled={pending}
primary
className={cn(
"[:where(&:disabled>svg:nth-child(2))]:hidden",
className
)}
{...props}
>
{pending && <MingcuteLoading3Fill className="animate-spin" />}
{props.children}
</Button>
)
}
export function MingcuteLoading3Fill(props: SVGProps<SVGSVGElement>) {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" {...props}>{/* Icon from MingCute Icon by MingCute Design - https://github.com/Richard9394/MingCute/blob/main/LICENSE */}<g fill="none" fillRule="evenodd"><path d="m12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.018-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"></path><path fill="currentColor" d="M12 4.5a7.5 7.5 0 1 0 0 15a7.5 7.5 0 0 0 0-15M1.5 12C1.5 6.201 6.201 1.5 12 1.5S22.5 6.201 22.5 12S17.799 22.5 12 22.5S1.5 17.799 1.5 12" opacity=".1"></path><path fill="currentColor" d="M12 4.5a7.46 7.46 0 0 0-5.187 2.083a1.5 1.5 0 0 1-2.075-2.166A10.46 10.46 0 0 1 12 1.5a1.5 1.5 0 0 1 0 3"></path></g></svg>
)
}

Link Button

A button that works as a link.

Show Code
<Button asChild outline>
<a href="https://www.v0.dev/" target="_blank">
Open in
<SimpleIconsV0 />
</a>
</Button>

Rounded

A button with fully rounded corners.

Show Code
<Button primary lg className="rounded-full px-5">
<RiVercelFill />
Start Deploying
</Button>