Initiates an action, such as completing a task or submitting information.
Default
Neutral
Danger
1import { Button } from "@ngrok/mantle/button";2 3<Button>Outlined</Button>4<Button appearance="filled">Filled</Button>5<Button appearance="ghost">Ghost</Button>6<Button appearance="link">Link</Button>7 8<Button priority="neutral">Outlined</Button>9<Button priority="neutral" appearance="filled">Filled</Button>10<Button priority="neutral" appearance="ghost">Ghost</Button>11<Button priority="neutral" appearance="link">Link</Button>12 13<Button priority="danger">Outlined</Button>14<Button priority="danger" appearance="filled">Filled</Button>15<Button priority="danger" appearance="ghost">Ghost</Button>16<Button priority="danger" appearance="link">Link</Button>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.
1// ✅ Opts in — submits the form2<Button type="submit" appearance="filled">Save</Button>3 4// ❌ Defaults to type="button" — native form submission never fires5<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.
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.
1import { Button } from "@ngrok/mantle/button";2import { FireIcon } from "@phosphor-icons/react/Fire";3 4<Button icon={<FireIcon weight="fill" />}>Icon Start</Button>5<Button icon={<FireIcon weight="fill" />} iconPlacement="end">6 Icon End7</Button>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.
Idle
isLoading
1import { Button } from "@ngrok/mantle/button";2import { FireIcon } from "@phosphor-icons/react/Fire";3 4<Button>No Icon + Idle</Button>5<Button icon={<FireIcon weight="fill" />}>Icon Start + Idle</Button>6<Button icon={<FireIcon weight="fill" />} iconPlacement="end">7 Icon End + Idle8</Button>9<Button isLoading>No Icon + isLoading</Button>10<Button icon={<FireIcon weight="fill" />} isLoading>11 Icon Start + isLoading12</Button>13<Button icon={<FireIcon weight="fill" />} iconPlacement="end" isLoading>14 Icon End + isLoading15</Button>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.
1import { Button } from "@ngrok/mantle/button";2import { FireIcon } from "@phosphor-icons/react/Fire";3import { Link, href } from "react-router";4 5<Button appearance="filled" icon={<FireIcon weight="fill" />} asChild>6 <Link to={href("/base/colors")}>See our colors!</Link>7</Button>;All props from button, plus: