---
title: Button
description: Initiates an action, such as completing a task or submitting information.
---

# Button

Initiates an action, such as completing a task or submitting information.

```tsx
import { Button } from "@ngrok/mantle/button";

<Button>Outlined</Button>
<Button appearance="filled">Filled</Button>
<Button appearance="ghost">Ghost</Button>
<Button appearance="link">Link</Button>

<Button priority="neutral">Outlined</Button>
<Button priority="neutral" appearance="filled">Filled</Button>
<Button priority="neutral" appearance="ghost">Ghost</Button>
<Button priority="neutral" appearance="link">Link</Button>

<Button priority="danger">Outlined</Button>
<Button priority="danger" appearance="filled">Filled</Button>
<Button priority="danger" appearance="ghost">Ghost</Button>
<Button priority="danger" appearance="link">Link</Button>
```

## Type

Unlike the native `<button>` element — which defaults to `type="submit"` — a mantle `Button` defaults to **`type="button"`**. This matches the wider React ecosystem (Radix, shadcn, MUI, …) and stops a button from accidentally submitting a surrounding `<form>` when all you wanted was an `onClick`.

The tradeoff: a button that *should* submit a form has to opt in with `type="submit"` (or `type="reset"` to reset it). A plain `<Button>` that relies on native form submission will silently do nothing.

```tsx
// ✅ Opts in — submits the form
<Button type="submit" appearance="filled">Save</Button>

// ❌ Defaults to type="button" — native form submission never fires
<Button appearance="filled">Save</Button>
```

When `asChild` is used, `type` has no effect and is not forwarded to the child, so a wrapped anchor never inherits a `button` `type`.

## Icon and Positioning

Use the `icon` prop to add an icon to the button. By default, it will render on the logical start side of the button. Use the `iconPlacement` prop to change the side the icon is rendered on.

```tsx
import { Button } from "@ngrok/mantle/button";
import { FireIcon } from "@phosphor-icons/react/Fire";

<Button icon={<FireIcon weight="fill" />}>Icon Start</Button>
<Button icon={<FireIcon weight="fill" />} iconPlacement="end">
	Icon End
</Button>
```

## isLoading

`isLoading` determines whether or not the button is in a loading state, default `false`. Setting `isLoading` will replace any `icon` with a spinner, or add one if an icon wasn't given. It will also disable user interaction with the button and set `aria-disabled`.

```tsx
import { Button } from "@ngrok/mantle/button";
import { FireIcon } from "@phosphor-icons/react/Fire";

<Button>No Icon + Idle</Button>
<Button icon={<FireIcon weight="fill" />}>Icon Start + Idle</Button>
<Button icon={<FireIcon weight="fill" />} iconPlacement="end">
	Icon End + Idle
</Button>
<Button isLoading>No Icon + isLoading</Button>
<Button icon={<FireIcon weight="fill" />} isLoading>
	Icon Start + isLoading
</Button>
<Button icon={<FireIcon weight="fill" />} iconPlacement="end" isLoading>
	Icon End + isLoading
</Button>
```

## Polymorphism

When you want to render *something else* as a `Button`, you can use the `asChild` prop to compose. This is useful when you want to splat the `Button` styling onto a `react-router` `Link`. Keep in mind that when you use `asChild` the `type` prop will **NOT** be passed to the child component.

```tsx
import { Button } from "@ngrok/mantle/button";
import { FireIcon } from "@phosphor-icons/react/Fire";
import { Link, href } from "react-router";

<Button appearance="filled" icon={<FireIcon weight="fill" />} asChild>
	<Link to={href("/base/colors")}>See our colors!</Link>
</Button>;
```

## API Reference

### Button

All props from [button](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attributes), plus:

| Prop             | Type                                                | Default      | Description                                                                                                                                                                                                                                                                                                                                                            |
| ---------------- | --------------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `appearance?`    | `"ghost"` \| `"filled"` \| `"outlined"` \| `"link"` | `"outlined"` | Defines the visual style of the `Button`.                                                                                                                                                                                                                                                                                                                              |
| `asChild?`       | `boolean`                                           | `false`      | Use the `asChild` prop to compose the `Button` styling onto alternative element types or your own React components.                                                                                                                                                                                                                                                    |
| `icon?`          | `ReactNode`                                         |              | An icon to render inside the button. When `isLoading` is `true`, the icon will automatically be replaced with a spinner.                                                                                                                                                                                                                                               |
| `iconPlacement?` | `"start"` \| `"end"`                                | `"start"`    | The side that the icon will render on, if one is present. When `isLoading` is `true`, the loading spinner will also render on this side.                                                                                                                                                                                                                               |
| `isLoading?`     | `boolean`                                           | `false`      | Determines whether or not the button is in a loading state. Setting `isLoading` will replace any `icon` with a spinner, or add one if an icon wasn't given. It will also disable user interaction with the button and set `aria-disabled`.                                                                                                                             |
| `priority?`      | `"default"` \| `"danger"` \| `"neutral"`            | `"default"`  | Indicates the importance or impact level of the button, affecting its color and styling to communicate its purpose to the user.                                                                                                                                                                                                                                        |
| `type?`          | `"button"` \| `"reset"` \| `"submit"`               | `"button"`   | The behavior of the `Button` when activated. Defaults to `"button"`, so a `Button` inside a `<form>` will **not** submit it — pass `type="submit"` to submit the form. When `asChild` is used, `type` has no effect and is not forwarded to the child. See [the MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#type) for more information. |
