HapplyUI

Components

Button

A compound button component with variants, modes, sizes, and polymorphic icon support.


Installation

bunx @happlyui/cli@latest add button

Dependencies

npm packages

  • @radix-ui/react-slot

Registry dependencies

These are automatically installed when you add this component.

  • tv
  • polymorphic
  • recursive-clone-children
  • loader

Usage

import * as Button from "@/components/ui/button"

<Button.Root variant="primary" mode="filled">
  <Button.Icon as={MailIcon} />
  Send Email
</Button.Root>

Examples

Primary Variant

The primary variant uses the brand color for main call-to-action buttons.

<Button.Root variant="primary" mode="filled">Get Started</Button.Root>
<Button.Root variant="primary" mode="stroke">Get Started</Button.Root>
<Button.Root variant="primary" mode="lighter">Get Started</Button.Root>
<Button.Root variant="primary" mode="ghost">Get Started</Button.Root>

Neutral Variant

The neutral variant uses grayscale colors for secondary actions.

<Button.Root variant="neutral" mode="filled">Learn More</Button.Root>
<Button.Root variant="neutral" mode="stroke">Learn More</Button.Root>
<Button.Root variant="neutral" mode="lighter">Learn More</Button.Root>
<Button.Root variant="neutral" mode="ghost">Learn More</Button.Root>

Success Variant

The success variant for positive or confirmation actions.

<Button.Root variant="success" mode="filled">Try Again</Button.Root>
<Button.Root variant="success" mode="stroke">Try Again</Button.Root>
<Button.Root variant="success" mode="lighter">Try Again</Button.Root>
<Button.Root variant="success" mode="ghost">Try Again</Button.Root>

Warning Variant

The warning variant for cautionary actions.

<Button.Root variant="warning" mode="filled">Try Again</Button.Root>
<Button.Root variant="warning" mode="stroke">Try Again</Button.Root>
<Button.Root variant="warning" mode="lighter">Try Again</Button.Root>
<Button.Root variant="warning" mode="ghost">Try Again</Button.Root>

Error Variant

The error variant for destructive actions.

<Button.Root variant="error" mode="filled">Try Again</Button.Root>
<Button.Root variant="error" mode="stroke">Try Again</Button.Root>
<Button.Root variant="error" mode="lighter">Try Again</Button.Root>
<Button.Root variant="error" mode="ghost">Try Again</Button.Root>

Sizes

Buttons come in multiple sizes across all modes.

<Button.Root size="medium">Medium</Button.Root>
<Button.Root size="small">Small</Button.Root>
<Button.Root size="xsmall">Xsmall</Button.Root>
<Button.Root size="xxsmall">Xxsmall</Button.Root>

Disabled

Disabled buttons across all modes.

<Button.Root disabled>Disabled</Button.Root>
<Button.Root mode="stroke" disabled>Disabled</Button.Root>

With Icon

Use Button.Icon with the `as` prop for polymorphic icon rendering.

<Button.Root>
  Button
  <Button.Icon as={RiArrowRightSLine} />
</Button.Root>

<Button.Root>
  <Button.Icon as={RiFileCopyLine} />
</Button.Root>

Full Width

Buttons can stretch to fill their container with a className override.

<Button.Root variant="neutral" className="w-full">
  Learn More
</Button.Root>

As Child

Use the asChild prop with Radix Slot to render as a different element, such as a link.

<Button.Root asChild>
  <a href="#">As link</a>
</Button.Root>

Loading

Use the loading prop to trigger an animated transition. The original text wave-blurs out letter by letter, then a spinner and "Loading..." wave-blurs in with a continuous typewriter dot effect.

<Button.Root loading>Get Started</Button.Root>

Loading Interactive

Click the button to see the full loading animation in action. The state resets after 3 seconds.

<Button.Root loading={loading} onClick={handleClick}>
  Get Started
</Button.Root>

Composed

Simplified usage via the Composed wrapper with leadingIcon and trailingIcon props.

<Button.Composed
  leadingIcon={RiArrowLeftSLine}
  trailingIcon={RiArrowRightSLine}
  variant="neutral"
  mode="stroke"
>
  Button
</Button.Composed>

API Reference

Button.Root

The main button component.

PropTypeDefaultDescription
variant'primary' | 'neutral' | 'error' | 'warning' | 'success''primary'The color variant
mode'filled' | 'stroke' | 'lighter' | 'ghost''filled'The visual style
size'medium' | 'small' | 'xsmall' | 'xxsmall''medium'The size of the button
asChildbooleanfalseRenders as child element using Radix Slot
loadingbooleanfalseTriggers an animated loading transition with a wave text effect, spinner, and typewriter dots
loadingTextstring'Loading'Override the loading text displayed during the loading animation. The '...' dots are appended automatically.
disabledbooleanfalseDisables the button

Button.Icon

Polymorphic icon container that receives variant props from Button.Root.

PropTypeDefaultDescription
asReact.ElementType'div'The element or component to render as

Button.Composed

A simplified wrapper that composes Root and Icon into a single component.

PropTypeDefaultDescription
leadingIconReact.ElementType-Icon rendered before the children
trailingIconReact.ElementType-Icon rendered after the children
variant'primary' | 'neutral' | 'error' | 'warning' | 'success''primary'The color variant
mode'filled' | 'stroke' | 'lighter' | 'ghost''filled'The visual style
size'medium' | 'small' | 'xsmall' | 'xxsmall''medium'The size of the button

Previous
Installation