> ## Documentation Index
> Fetch the complete documentation index at: https://araf.badr.co.id/llms.txt
> Use this file to discover all available pages before exploring further.

# Button

> An interactive button for triggering actions — available in multiple hierarchies, sizes, and states.

## Overview

<div style={{display:"flex",gap:"12px",padding:"28px 24px",background:"#f9fafb",borderRadius:"12px",flexWrap:"wrap",alignItems:"center",border:"1px solid #e5e7eb"}}>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Primary</button>
  <button style={{background:"#F0F9FF",color:"#045CA0",border:"1px solid #F0F9FF",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Secondary</button>
  <button style={{background:"#fff",color:"#52525B",border:"1px solid #D4D4D8",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Secondary Gray</button>
  <button style={{background:"transparent",color:"#045CA0",border:"none",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer"}}>Tertiary</button>
  <button style={{background:"transparent",color:"#52525B",border:"none",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer"}}>Tertiary Gray</button>
  <button style={{background:"#DC2626",color:"#fff",border:"1px solid #DC2626",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Destructive</button>
  <button style={{background:"transparent",color:"#045CA0",border:"none",padding:"10px 4px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",textDecoration:"underline"}}>Link</button>
</div>

The **Button** component is the primary interactive element in the A'raf Design System. It can render as a `<button>` or `<a>` tag automatically depending on whether the `href` prop is provided.

***

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @araf-ds/core
  ```

  ```bash yarn theme={null}
  yarn add @araf-ds/core
  ```

  ```bash pnpm theme={null}
  pnpm add @araf-ds/core
  ```
</CodeGroup>

***

## Usage

```tsx theme={null}
import { Button } from "@araf-ds/core"

export default function Example() {
  return <Button>Click me</Button>
}
```

***

## Variants

Button has **7 visual hierarchies** reflecting the level of action emphasis.

### Primary

Used for the primary and most important action on a page. Use sparingly — one per view at most.

<div style={{display:"flex",gap:"12px",padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",flexWrap:"wrap",alignItems:"center"}}>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Save changes</button>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"not-allowed",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)",opacity:0.4}}>Disabled</button>
</div>

```tsx theme={null}
<Button color="primary">Save changes</Button>
<Button color="primary" isDisabled>Disabled</Button>
```

<CardGroup cols={2}>
  <Card title="When to use">
    * Primary form submission
    * Page-level CTA
    * Irreversible actions
  </Card>

  <Card title="When not to use">
    * More than one important action in the same area
    * Secondary or tertiary actions
  </Card>
</CardGroup>

### Secondary

Two variants: `secondary` with a light blue background and `secondary-gray` with a gray border. Use alongside Primary for alternative actions.

<div style={{display:"flex",gap:"12px",padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",flexWrap:"wrap",alignItems:"center"}}>
  <button style={{background:"#F0F9FF",color:"#045CA0",border:"1px solid #F0F9FF",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Secondary</button>
  <button style={{background:"#fff",color:"#52525B",border:"1px solid #D4D4D8",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Secondary Gray</button>
  <button style={{background:"#F0F9FF",color:"#045CA0",border:"1px solid #F0F9FF",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"not-allowed",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)",opacity:0.4}}>Disabled</button>
</div>

```tsx theme={null}
<Button color="secondary">Secondary</Button>
<Button color="secondary-gray">Secondary Gray</Button>
```

### Tertiary

A borderless button that looks like plain text but retains an interactive hit area. Use for tertiary actions that don't need visual prominence.

<div style={{display:"flex",gap:"12px",padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",flexWrap:"wrap",alignItems:"center"}}>
  <button style={{background:"transparent",color:"#045CA0",border:"none",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer"}}>Tertiary</button>
  <button style={{background:"transparent",color:"#52525B",border:"none",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer"}}>Tertiary Gray</button>
  <button style={{background:"transparent",color:"#045CA0",border:"none",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"not-allowed",opacity:0.4}}>Disabled</button>
</div>

```tsx theme={null}
<Button color="tertiary">Tertiary</Button>
<Button color="tertiary-gray">Tertiary Gray</Button>
```

### Link

Appears as a hyperlink. Available in two colors: `link-color` and `link-gray`.

<div style={{display:"flex",gap:"12px",padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",flexWrap:"wrap",alignItems:"center"}}>
  <button style={{background:"transparent",color:"#045CA0",border:"none",padding:"10px 4px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",textDecoration:"underline"}}>Link color</button>
  <button style={{background:"transparent",color:"#52525B",border:"none",padding:"10px 4px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",textDecoration:"underline"}}>Link gray</button>
</div>

```tsx theme={null}
<Button color="link-color">View profile</Button>
<Button color="link-gray">Terms of service</Button>
```

<Note>
  Add the `href` prop to make this button render as an anchor tag for navigation.
</Note>

### Destructive

Red variant for dangerous or permanent actions. Available across all hierarchies.

<div style={{display:"flex",gap:"12px",padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",flexWrap:"wrap",alignItems:"center"}}>
  <button style={{background:"#DC2626",color:"#fff",border:"1px solid #DC2626",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Delete account</button>
  <button style={{background:"#FEF2F2",color:"#DC2626",border:"1px solid #FEF2F2",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Remove</button>
  <button style={{background:"transparent",color:"#DC2626",border:"none",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer"}}>Discard</button>
</div>

```tsx theme={null}
<Button color="primary-destructive">Delete account</Button>
<Button color="secondary-destructive">Remove</Button>
<Button color="tertiary-destructive">Discard changes</Button>
```

<Warning>
  Always add a confirmation dialog before triggering a destructive action.
</Warning>

***

## Sizes

**5 sizes** are available to match different layout contexts.

<div style={{display:"flex",gap:"12px",padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",flexWrap:"wrap",alignItems:"center"}}>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"8px 14px",fontWeight:500,fontSize:"12px",lineHeight:"18px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Small</button>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Medium</button>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 18px",fontWeight:500,fontSize:"16px",lineHeight:"24px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Large</button>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"12px 20px",fontWeight:500,fontSize:"16px",lineHeight:"24px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Extra Large</button>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"14px 28px",fontWeight:500,fontSize:"18px",lineHeight:"28px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>2X Large</button>
</div>

| Size        | Prop  | Height | Use case                        |
| ----------- | ----- | ------ | ------------------------------- |
| Small       | `sm`  | 36px   | Tables, dense toolbars          |
| Medium      | `md`  | 40px   | Default — forms, cards, dialogs |
| Large       | `lg`  | 44px   | Hero sections, landing pages    |
| Extra Large | `xl`  | 48px   | Marketing pages                 |
| 2X Large    | `2xl` | 56px   | Full-width CTAs, splash screens |

```tsx theme={null}
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
<Button size="xl">Extra Large</Button>
<Button size="2xl">2X Large</Button>
```

<Tip>
  Keep sizes consistent within a single UI context. Do not mix `sm` and `xl` in the same toolbar.
</Tip>

***

## States

<div style={{display:"flex",gap:"12px",padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",flexWrap:"wrap",alignItems:"center"}}>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Default</button>
  <button style={{background:"#045CA0",color:"#fff",border:"1px solid #045CA0",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)"}}>Hover</button>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05), 0px 0px 0px 4px #CDE4F5"}}>Focused</button>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"not-allowed",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)",opacity:0.4}}>Disabled</button>

  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)",display:"flex",alignItems:"center",gap:"8px"}}>
    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" style={{animation:"spin 1s linear infinite"}}>
      <path d="M21 12a9 9 0 1 1-6.219-8.56" />
    </svg>

    Loading
  </button>
</div>

<style>
  {`@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }`}
</style>

| State    | Prop         | Description                                         |
| -------- | ------------ | --------------------------------------------------- |
| Default  | —            | Normal appearance                                   |
| Hover    | —            | Background becomes `#045CA0`, handled automatically |
| Focused  | —            | Ring `4px #CDE4F5` for keyboard navigation          |
| Disabled | `isDisabled` | Opacity `0.4`, cursor `not-allowed`                 |
| Loading  | `isLoading`  | Spinner scales to match button size and color       |

```tsx theme={null}
<Button>Default</Button>
<Button isDisabled>Disabled</Button>
<Button isLoading>Loading</Button>
<Button isLoading showTextWhileLoading>Saving changes</Button>
```

<Note>
  Avoid hiding a button when it is unavailable. Use `isDisabled` so users can still see the action exists.
</Note>

***

## Icons

Button supports icons on the left, right, or in icon-only mode.

<div style={{display:"flex",gap:"12px",padding:"24px",background:"#f9fafb",borderRadius:"12px",border:"1px solid #e5e7eb",flexWrap:"wrap",alignItems:"center"}}>
  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)",display:"flex",alignItems:"center",gap:"8px"}}>
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
      <path d="M12 5v14M5 12h14" />
    </svg>

    New item
  </button>

  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px 16px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)",display:"flex",alignItems:"center",gap:"8px"}}>
    Continue

    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
      <path d="M5 12h14M12 5l7 7-7 7" />
    </svg>
  </button>

  <button style={{background:"#0479CE",color:"#fff",border:"1px solid #0479CE",borderRadius:"8px",padding:"10px",fontWeight:500,fontSize:"14px",lineHeight:"20px",cursor:"pointer",boxShadow:"0px 1px 2px rgba(16,24,40,0.05)",display:"flex",alignItems:"center"}} aria-label="Add new item">
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
      <path d="M12 5v14M5 12h14" />
    </svg>
  </button>
</div>

```tsx theme={null}
import { Button } from "@araf-ds/core"
import { PlusIcon, ArrowRightIcon } from "@araf-ds/core/icons"

// Leading icon
<Button iconLeading={PlusIcon}>New item</Button>

// Trailing icon
<Button iconTrailing={ArrowRightIcon}>Continue</Button>

// Icon only — aria-label required
<Button iconLeading={PlusIcon} aria-label="Add new item" />
```

<Warning>
  For **icon-only** mode, always add an `aria-label` prop so screen readers can identify the button's action.
</Warning>

***

## As Link

Button renders as an `<a>` tag simply by adding the `href` prop.

```tsx theme={null}
// Internal navigation
<Button href="/dashboard">Go to dashboard</Button>

// External link
<Button href="https://example.com" target="_blank" rel="noopener noreferrer">
  Open docs
</Button>
```

***

## API Reference

<ParamField path="color" type="string" default="primary">
  Visual hierarchy of the button. Values:
  `primary` · `secondary` · `secondary-gray` · `tertiary` · `tertiary-gray` · `link-color` · `link-gray` · `primary-destructive` · `secondary-destructive` · `tertiary-destructive` · `link-destructive`
</ParamField>

<ParamField path="size" type="string" default="md">
  Button size. Values: `sm` · `md` · `lg` · `xl` · `2xl`
</ParamField>

<ParamField path="isDisabled" type="boolean" default="false">
  Disables interaction and applies the disabled visual state.
</ParamField>

<ParamField path="isLoading" type="boolean" default="false">
  Shows a loading spinner and prevents interaction.
</ParamField>

<ParamField path="showTextWhileLoading" type="boolean" default="false">
  When `true`, the children text remains visible during `isLoading`.
</ParamField>

<ParamField path="iconLeading" type="ComponentType">
  Icon component rendered to the left of the label. Without `children`, the button becomes icon-only.
</ParamField>

<ParamField path="iconTrailing" type="ComponentType">
  Icon component rendered to the right of the label.
</ParamField>

<ParamField path="href" type="string">
  When provided, the button renders as an `<a>` anchor tag.
</ParamField>

<ParamField path="className" type="string">
  Additional Tailwind classes for custom overrides.
</ParamField>

***

## Accessibility

* Uses a semantic `<button>` element by default
* The `disabled` state is handled with the native `disabled` attribute
* Keyboard focus is shown with a `4px #CDE4F5` outline ring
* Icon-only mode **requires** an `aria-label`
* When rendered as a link (`href`), full anchor semantics apply

***

## Do's & Don'ts

<CardGroup cols={2}>
  <Card title="Do" icon="check" iconType="solid" color="#16A34A">
    * Use **Primary** for one main action per page
    * Pair Primary + Secondary for confirm/cancel actions
    * Always add `aria-label` on icon-only buttons
    * Use the Destructive variant for irreversible actions
  </Card>

  <Card title="Don't" icon="xmark" iconType="solid" color="#DC2626">
    * Don't use more than one Primary button in the same section
    * Don't use custom colors outside the design system
    * Don't hide a disabled button — use the `isDisabled` prop instead
    * Don't use the Link variant for actions that modify data
  </Card>
</CardGroup>
