Button

free

Button gives product actions a consistent hierarchy across forms, dialogs, and toolbars.

Preview
Dark
import Button from '@/components/ui/Button';

export default function UsageDemo() {
  return (
    <div className="inline-flex flex-wrap items-center justify-center gap-2">
      <Button variant="solid">Save changes</Button>
      <Button>Cancel</Button>
    </div>
  );
}

Installation

Add this component with the NateUI CLI.

npx nateui@latest add Button

Examples

Variants

Preview
Dark
import Button from '@/components/ui/Button';

export default function VariantDemo() {
  return (
    <div className="inline-flex flex-wrap items-center justify-center gap-2">
      <Button>Default</Button>
      <Button variant="solid">Solid</Button>
      <Button variant="subtle">Subtle</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="link">Link</Button>
    </div>
  );
}

Sizes

Preview
Dark
import Button from '@/components/ui/Button';

export default function SizeDemo() {
  return (
    <div className="inline-flex flex-wrap items-center justify-center gap-2">
      <Button size="sm">Small</Button>
      <Button size="md">Medium</Button>
      <Button size="lg">Large</Button>
    </div>
  );
}

Shapes

Preview
Dark
import { PiPlus } from 'react-icons/pi'
import Button from '@/components/ui/Button';

export default function ShapeDemo() {
  return (
    <div className="inline-flex flex-wrap items-center justify-center gap-2">
      <Button shape="round">Round</Button>
      <Button shape="none">None</Button>
      <Button shape="circle" icon={<PiPlus />} aria-label="Add item" />
    </div>
  );
}

States

Preview
Dark
import Button from '@/components/ui/Button';

export default function StatesDemo() {
  return (
    <div className="inline-flex flex-wrap items-center justify-center gap-2">
      <Button active>Active</Button>
      <Button disabled>Disabled</Button>
      <Button loading>Loading</Button>
    </div>
  );
}

Destructive

Preview
Dark
import Button from '@/components/ui/Button';

export default function DestructiveDemo() {
  return (
    <div className="inline-flex flex-wrap items-center justify-center gap-2">
      <Button destructive>Default</Button>
      <Button destructive variant="solid">
        Solid
      </Button>
      <Button destructive variant="subtle">
        Subtle
      </Button>
      <Button destructive variant="ghost">
        Ghost
      </Button>
      <Button destructive variant="link">
        Link
      </Button>
    </div>
  );
}

Icons

Preview
Dark
import { PiArrowRight, PiEnvelope, PiPlus } from 'react-icons/pi'
import Button from '@/components/ui/Button';

export default function IconDemo() {
  return (
    <div className="inline-flex flex-wrap items-center justify-center gap-2">
      <Button icon={<PiEnvelope />}>Start icon</Button>
      <Button icon={<PiArrowRight />} iconAlignment="end">
        End icon
      </Button>
      <Button icon={<PiPlus />} aria-label="Add item" />
    </div>
  );
}

Block

Preview
Dark
import Button from '@/components/ui/Button';

export default function BlockDemo() {
  return (
    <div className="w-80 max-w-full space-y-2">
      <Button block variant="solid">
        Full width action
      </Button>
      <Button block>Secondary action</Button>
    </div>
  );
}

API

Button accepts the props below plus native props for the rendered element.

PropDescriptionTypeDefault
asElementRoot element or component rendered by the button.ElementType'button'
activeMarks the button as active and applies the active visual state.booleanfalse
blockExpands the button to the full width of its container.booleanfalse
childrenButton label or content.ReactNode-
classNameStatic class string or state-aware class callback.ButtonClassName-
clickFeedbackEnables the press-down transform feedback on activation.booleantrue
destructiveSwitches the button into the destructive intent palette.booleanfalse
disabledPrevents interaction and applies the disabled visual state.booleanfalse
iconIcon content rendered with, or instead of, the label.string | ReactNode-
iconAlignmentIcon placement when both icon and label are present.ButtonIconAlignment'start'
loadingShows a spinner and prevents repeat activation.booleanfalse
onClickClick handler invoked only when the button is not disabled or loading.ButtonClickHandler-
refRef forwarded to the underlying button element.Ref<HTMLButtonElement>-
shapeBorder radius treatment.ButtonShape'round'
sizeControl size. Falls back to InputGroup size, then ConfigProvider control size.ControlSize'md' from ConfigProvider
variantVisual style.ButtonVariant'default'
...nativePropsNative props for the rendered element, excluding Button-owned props.NativeButtonProps<E>-

Types

type ButtonVariant = 'solid' | 'subtle' | 'default' | 'ghost' | 'link';
type ControlSize = 'sm' | 'md' | 'lg';
type ButtonShape = 'round' | 'circle' | 'none';
type ButtonIconAlignment = 'start' | 'end';
type ButtonClickHandler = (event: MouseEvent<HTMLButtonElement>) => void;
 
type ButtonClassName =
  | string
  | ((state: {
      active: boolean;
      destructive: boolean;
      unclickable: boolean;
    }) => string);
 
type NativeButtonProps<E extends ElementType> = Omit<
  ComponentPropsWithoutRef<E>,
  | 'asElement'
  | 'active'
  | 'block'
  | 'className'
  | 'clickFeedback'
  | 'destructive'
  | 'disabled'
  | 'icon'
  | 'iconAlignment'
  | 'loading'
  | 'onClick'
  | 'ref'
  | 'shape'
  | 'size'
  | 'variant'
>;