> Leaf UI 0.6.0 · Package: @ifhover/leaf-ui · Source: b30c3d3a8fa9c5e15d0d0522cebfbd33f60c6b06
> Browser documentation: https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/button.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/v/0.6.0/en/llms-full.txt.

# Button

Trigger an action, such as saving, submitting or deleting.

## Examples

Use solid for primary actions, outline for secondary actions with a white surface and a fine border, and ghost for low-priority actions. Link buttons use the theme color without padding, border or a fixed control height; use the Link component for navigation. Loading preserves the label and prevents duplicate clicks. Set type="submit" for form submission, and aria-label for icon-only actions.

On activation, solid and outlined buttons emit a wave that quickly expands outside the button and slowly fades while the button and label stay still. Ghost and link buttons do not emit a wave. Solid buttons brighten on hover and deepen on press; outlined buttons keep their surface and change their text and border colors. Danger actions use red. The wave follows the theme and respects regional and system motion preferences.


PrimaryOutlineGhostLink

variants.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/button/variants.tsx"
import { Button, Space } from '@ifhover/leaf-ui';

export function ButtonVariants() {
  return (
    <Space wrap>
      <Button>Primary</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="link">Link</Button>
    </Space>
  );
}
```

Expand code


Delete projectRevoke accessClearDeletion disabledDeleting

danger.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/button/danger.tsx"
import { Button, Space } from '@ifhover/leaf-ui';

import { Trash2 } from 'lucide-react';

export function ButtonDanger() {
  return (
    <Space wrap>
      <Button danger startIcon={<Trash2 />}>
        Delete project
      </Button>
      <Button danger variant="outline">
        Revoke access
      </Button>
      <Button danger variant="ghost">
        Clear
      </Button>
      <Button danger disabled>
        Deletion disabled
      </Button>
      <Button danger loading>
        Deleting
      </Button>
    </Space>
  );
}
```

Expand code


SmallDefaultLarge

sizes.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/button/sizes.tsx"
import { Button, Space } from '@ifhover/leaf-ui';

export function ButtonSizes() {
  return (
    <Space wrap>
      <Button size="sm">Small</Button>
      <Button size="md">Default</Button>
      <Button size="lg">Large</Button>
    </Space>
  );
}
```

Expand code


UnavailableLoadingDisabled

states.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/button/states.tsx"
import { Button, Space } from '@ifhover/leaf-ui';

export function ButtonStates() {
  return (
    <Space wrap>
      <Button disabled>Unavailable</Button>
      <Button loading>Loading</Button>
      <Button variant="outline" disabled>
        Disabled
      </Button>
    </Space>
  );
}
```

Expand code


Save changesTry saving changes.

loading.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/button/loading.tsx"
import { Button, Space } from '@ifhover/leaf-ui';

import { useEffect, useRef, useState } from 'react';

export function ButtonLoading() {
  const [status, setStatus] = useState<'idle' | 'loading' | 'saved'>('idle');
  const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);

  useEffect(() => () => clearTimeout(timer.current), []);

  function save() {
    clearTimeout(timer.current);
    setStatus('loading');
    // This example simulates a request; replace it with your application request.
    timer.current = setTimeout(() => setStatus('saved'), 1200);
  }

  return (
    <Space wrap>
      <Button loading={status === 'loading'} onClick={save}>
        {status === 'loading' ? 'Saving' : status === 'saved' ? 'Save again' : 'Save changes'}
      </Button>
      <span role="status">{status === 'saved' ? 'Changes saved.' : 'Try saving changes.'}</span>
    </Space>
  );
}
```

Expand code


New projectContinue

icons.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/button/icons.tsx"
import { Button, Space } from '@ifhover/leaf-ui';

import { ArrowRight, Plus, Trash2 } from 'lucide-react';

export function ButtonIcons() {
  return (
    <Space wrap>
      <Button startIcon={<Plus />}>New project</Button>
      <Button variant="outline" endIcon={<ArrowRight />}>
        Continue
      </Button>
      <Button variant="outline" aria-label="Add project" startIcon={<Plus />} />
      <Button danger variant="outline" aria-label="Delete project" startIcon={<Trash2 />} />
    </Space>
  );
}
```

Expand code


Continue

full-width.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/button/full-width.tsx"
import { Button } from '@ifhover/leaf-ui';

export function ButtonFullWidth() {
  return <Button fullWidth>Continue</Button>;
}
```

Expand code

## Extended features


Button groupPreviousNext

Split buttonSave

extensions.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/button/extensions.tsx"
import { Button, ButtonGroup, Flex, Space, SplitButton, Text } from '@ifhover/leaf-ui';

export function ExtensionDemo() {
  return (
    <Space direction="vertical" align="start">
      <Flex direction="column" gap="sm" align="center">
        <Text>Button group</Text>
        <ButtonGroup>
          <Button variant="outline">Previous</Button>
          <Button variant="outline">Next</Button>
        </ButtonGroup>
      </Flex>
      <Flex direction="column" gap="sm" align="center">
        <Text>Split button</Text>
        <SplitButton
          items={[
            { key: 'copy', label: 'Save a copy' },
            { key: 'draft', label: 'Save draft' },
          ]}
        >
          Save
        </SplitButton>
      </Flex>
    </Space>
  );
}
```

Expand code

## Button API

| Property    | Type                                        | Default    | Description                                          |
| ----------- | ------------------------------------------- | ---------- | ---------------------------------------------------- |
| `variant`   | `'solid' \| 'outline' \| 'ghost' \| 'link'` | `'solid'`  | Visual style                                         |
| `size`      | `'sm' \| 'md' \| 'lg'`                      | `'md'`     | Control size                                         |
| `danger`    | `boolean`                                   | `false`    | Danger colors; works with every variant              |
| `loading`   | `boolean`                                   | `false`    | Show loading and disable interaction                 |
| `fullWidth` | `boolean`                                   | `false`    | Fill the parent width                                |
| `startIcon` | `ReactNode`                                 | —          | Leading icon; replaced by the spinner during loading |
| `endIcon`   | `ReactNode`                                 | —          | Trailing icon                                        |
| `disabled`  | `boolean`                                   | `false`    | Disable interaction.                                 |
| `type`      | `'button' \| 'submit' \| 'reset'`           | `'button'` | Native button type                                   |
| `ref`       | `Ref<HTMLButtonElement>`                    | —          | DOM reference                                        |

## Types

Import ButtonProps to describe component props. Option types in the API table link to their detailed fields above.

```ts
import type { ButtonProps } from '@ifhover/leaf-ui';
```

## Forms and localization

Use name to include values in FormData. Uncontrolled fields follow form reset; reset controlled values in application state. Place controls in [FormField](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/form.md#formfield-api) for labels, help and errors. [ConfigProvider](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/config-provider.md) supplies regional themes and translated built-in UI. Application labels and options are your responsibility.

## Extension types

```ts
import type { ButtonGroupProps, SplitButtonProps } from '@ifhover/leaf-ui';
```

## ButtonGroupProps API

| Property   | Type                   | Default | Description            |
| ---------- | ---------------------- | ------- | ---------------------- |
| `size`     | `'sm' \| 'md' \| 'lg'` | —       | Size or spacing preset |
| `disabled` | `boolean`              | —       | Disable interaction.   |
| `attached` | `boolean`              | `true`  | Join adjacent buttons  |

## SplitButtonProps API

| Property        | Type                                                                                                                                               | Default  | Description                                  |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------- |
| `variant`       | `'solid' \| 'outline' \| 'ghost' \| 'link'`                                                                                                        | —        | Button appearance                            |
| `size`          | `'sm' \| 'md' \| 'lg'`                                                                                                                             | —        | Size or spacing preset                       |
| `danger`        | `boolean`                                                                                                                                          | —        | Danger colors                                |
| `loading`       | `boolean`                                                                                                                                          | —        | Loading state                                |
| `fullWidth`     | `boolean`                                                                                                                                          | —        | Fill available width                         |
| `startIcon`     | `ReactNode`                                                                                                                                        | —        | Leading icon                                 |
| `endIcon`       | `ReactNode`                                                                                                                                        | —        | Trailing icon                                |
| `items`         | `readonly `[`DropdownItem`](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/dropdown.md#dropdownitem)`[]`                                  | Required | Required. Items; keep keys unique and stable |
| `menuLabel`     | `string`                                                                                                                                           | —        | Accessible menu button label                 |
| `dropdownProps` | `Omit<`[`DropdownProps`](https://ifhover.github.io/leaf-ui/v/0.6.0/en/components/dropdown.md#dropdown-api)`, 'items' \| 'children' \| 'disabled'>` | —        | Action menu props                            |
