AntaButton MENU
On this page

Button

An action control. The Button JSX wrapper renders an <a-button> web component (or <a role="button"> when href is set). Tone, priority, size, and state are all plain attributes, so the styling is identical whether you use the wrapper or author the element by hand.

Play with it in playground.

Priorities

A button’s priority helps control how much attention it draws:

PublishMoveCancelRemind
<Button tone="brand" priority="primary" label="Publish" />
<Button tone="brand" priority="secondary" label="Move" />
<Button tone="brand" priority="tertiary" label="Cancel" />
<Button tone="brand" priority="quaternary" label="Remind" />
  • primary — Saturated fill. Main call to action.
  • secondary — Lighter background. Default priority.
  • tertiary — Background-less at rest, fills on hover.
  • quaternary — Text only, no background.

Tones

Six named tones — neutral (default), brand, critical, info, success, warning. Omitting tone — or passing an empty string — resolves to neutral. In addition, a custom tone is possible: pass any literal CSS color and the button will adapt to it.

SavePublishDeletePreviewApproveArchive
<Button label="Save" />
<Button tone="brand" label="Publish" />
<Button tone="critical" label="Delete" />
<Button tone="info" label="Preview" />
<Button tone="success" label="Approve" />
<Button tone="warning" label="Archive" />
PinkifyPinkifyPinkifyMintifyMintifyMintify
<Button priority="primary" tone="#ff1493" label="Pinkify" />
<Button priority="secondary" tone="oklch(0.655 0.261 356.9)" label="Pinkify" />
<Button priority="tertiary" tone="hsl(328 100% 54%)" label="Pinkify" />
<Button priority="primary" tone="mediumaquamarine" label="Mintify" />
<Button priority="secondary" tone="rgb(102 205 170)" label="Mintify" />
<Button priority="tertiary" tone="lch(75.7% 39.2 167.8)" label="Mintify" />
For custom tones, primary keeps the source’s hue and chroma but pins its lightness near the Brand primary’s, so any input — too light or too dark — still lands at a Brand-like fill (hover / active step the lightness, and the label keeps the standard primary text color). Secondary, tertiary, and quaternary take only its hue — lightness, chroma, and alpha come from the brand-tone curve (via oklch() relative color), so pale or low-chroma inputs (tone="#cccccc", tone="white") still produce a legible button. The full priority × state matrix — rest, hover, active, secondary alpha overlay, tertiary fill — is derived automatically, and re-tunes between light and dark.
If you need pixel-precise color, set --button-fg or --button-bg yourself — inline via style, or from your own class or selector. The resolver lives in @layer anta, so any un-layered rule of yours wins regardless of specificity (and inline beats everything). The same override also pins hover and active to that color — it overrides the per-state rules too, so there’s no state change; to keep distinct states, set the per-state variables instead — --button-bg-{priority}-hover, --button-bg-{priority}-active, and the --button-fg-* equivalents.

Sizes

SmallSmallMediumMediumLargeLarge
<Button tone="brand" size="small" label="Small" />
<Button tone="brand" size="medium" label="Medium" /> // default
<Button tone="brand" size="large" label="Large" />

Three sizes (medium is default); only the padding changes, so the label keeps the same 15px size — readability stays constant while the hit area grows or shrinks.

Height comes from line-height (18px) plus vertical padding, which is calibrated for 15px font-size of TT Interphases to get visual vertical centering.

sizeheightpadding-ytext-edge padding-xicon-edge padding-x
small24px3px7px5px
medium (default)28px5px9px7px
large32px7px13px11px

The icon-edge padding is the text-edge value minus 2px — an icon at an edge needs less breathing room than a glyph — so only the side a (leading or trailing) icon occupies is trimmed; the text side keeps the full padding. The gap between an icon and the label is 0.5ch at every size.

Need a different font size? Style the <a-button-label> directly — set its font-size and line-height, and (if the text then sits a little high) drop the 1px padding-bottom that optically centers Anta’s default font.

By default a button packs its content to the start, so when buttons share a width — a vertical menu, equal grid cells — their labels line up on a common left edge, which usually reads best in a list.

To center the label inside a wider button instead, set justify-content: center on it (the tones grid above does exactly this).

Paddingless

If you’re familiar with the basics, click here to skip the live demo.

If you're familiar with the basics, click
<Button tone="critical" priority="quaternary" paddingless label="here" />
to skip ahead to the live demo.
Only valid on priority="quaternary". Zeros the outer padding so the button sits flush with surrounding prose — useful when you want a button to read as an inline link inside a sentence.

Icons

ConfirmRead the docsFilter
<Button tone="brand" priority="primary" icon="check" label="Confirm" />
<Button tone="brand" iconTrailing="external-link" label="Read the docs" />
<Button tone="brand" priority="tertiary" icon="filter" iconTrailing="chevron-down" label="Filter" />
The wrapper renders content in this order inside the button: iconlabelchildreniconTrailing. Icon shape names come from the IconShape union — see the Icon page for the full set. children (if any) lands between label and iconTrailing.

Icon-only

<Button tone="neutral" icon="dots-vertical" size="small" />
<Button tone="critical" icon="trash" />
<Button tone="brand" icon="check" size="large" />

Pass icon alone — no label, no iconTrailing, no children — and the button collapses to a square. A min-size is pinned to a square matching the labeled-button height (24px / 28px / 32px for small / medium / large) so icon-only and labeled buttons line up, and a tight flex parent can’t clip the icon.

Icon-only buttons get an accessible name automatically — the wrapper sets aria-label={icon} so <Button icon="trash" /> ships with the name “trash”. Pass your own aria-label to override.

Children alongside label & icon

Save⌘S
<Button tone="brand" label="Save" icon="check">
<span style={{ opacity: 0.7 }}>⌘S</span>
</Button>

Children render after the label and before the trailing icon, so you can mix custom inline content — keyboard hints, badges, counters — with the prop-driven API.

Children also work without label — pass them as the only content.

Underline

SolidDashedDotted
<Button tone="brand" priority="tertiary" underline="solid" label="Solid" />
<Button tone="brand" priority="tertiary" underline="dashed" label="Dashed" />
<Button tone="brand" priority="tertiary" underline="dotted" label="Dotted" />
When the button has a link mode, or you simply want an underline stylistically, it supports three styles — solid, dashed, dotted (only valid on priority="tertiary" / "quaternary").

States

SubmittingLockedToggled onCritical
<Button tone="brand" loading label="Submitting" />
<Button tone="brand" disabled label="Locked" />
<Button tone="brand" selected label="Toggled on" />
<Button tone="brand" loading disabled label="Critical" />
  • loading — diagonal stripe overlay slides across the button. Stripe color follows currentColor, so it tracks the tone. Blocks clicks via pointer-events: none.
  • disabled — locks the colors to the disabled palette, sets pointer-events: none, and removes the button from the tab order. Beats inline --button-bg overrides.
  • selected — toggled-on / pressed visual; shares the active state’s look. Useful for filter chips and icon toggles.
<Button tone="brand" href="/docs" target="_blank" label="Read the docs" />
Setting href switches the rendered tag from <a-button> to <a role="button">. Styling is identical — both selectors share the same CSS rules.

Linking with routing libraries

Anta’s CSS targets a-button, a[role="button"] — an anchor (<a>) with role="button" and the right attributes gets the styling. That means anta doesn’t need an as / asChild / component prop or per-framework integrations. Compose your own thin wrapper around your library’s Link component — which renders an <a>, so it matches the selector.

// LinkButton.tsx — anta-styled link for client-side routing
import { Link, type LinkProps } from 'react-router-dom'
import type { IconShape } from '@antadesign/anta'
type LinkButtonProps = LinkProps & {
tone?: 'neutral' | 'brand' | 'critical' | 'info' | 'success' | 'warning'
priority?: 'primary' | 'secondary' | 'tertiary' | 'quaternary'
size?: 'small' | 'medium' | 'large'
icon?: IconShape
iconTrailing?: IconShape
label?: string
}
export const LinkButton = ({
tone, priority, size, icon, iconTrailing, label, children, ...rest
}: LinkButtonProps) => (
<Link role="button" tone={tone} priority={priority} size={size} {...rest}>
{icon && <a-icon shape={icon} aria-hidden="true" />}
{label != null && <a-button-label>{label}</a-button-label>}
{children}
{iconTrailing && <a-icon shape={iconTrailing} aria-hidden="true" />}
</Link>
)

Usage:

<LinkButton to="/dashboard" tone="brand" label="Dashboard" />
<LinkButton to="/docs" priority="tertiary" iconTrailing="external-link" label="Docs" />

This approach would work for Next.js <Link>, TanStack Router, or any other routing library.

Special events

Beyond a plain click, a Button can drive a native form or emit your own event:

Form submission

For non-anchor buttons, type="submit" and type="reset" integrate with native forms. type="submit" calls form.requestSubmit() and also dispatches a submitdetailed event on the form with { formData, submitter: { tag, attrs } } in detail — handy for analytics or multi-button forms.

Sign upClear
Submit from outside
<form id="signup">
<Button tone="brand" type="submit" label="Sign up" />
<Button tone="brand" priority="tertiary" type="reset" label="Clear" />
</form>
{/* Associate with a form by id when the button is outside */}
<Button tone="neutral" type="submit" form="signup" label="Submit from outside" />

Custom click events

data-custom-event="<name>" makes the button dispatch a bubbling CustomEvent("<name>") on click. Use it to instrument analytics without taking ownership of onClick.

Save
<Button tone="brand" label="Save" data-custom-event="save-clicked" />

Playground

Preview
priority
tone
size
label
icon
iconTrailing
href
target
children
className
style

Component props

PropTypeDefaultDescription
disabled?booleanDisable the button.
download?stringbooleanAnchor download attribute. Empty string / true triggers a download with the resource's default name; a string overrides the filename.
form?stringForm id when the button isn't a descendant of its form.
href?stringRenders as <a role="button"> instead of <a-button>.
icon?IconShapeLeading icon shape. When set alone (no label, no iconTrailing, no children), the button renders as a square icon-only control and the wrapper auto-supplies aria-label={icon} (override by passing your own aria-label).
iconTrailing?IconShapeTrailing icon shape. Renders after children, last in the slot order.
label?stringLabel text. Renders between the leading icon and children.
loading?booleanShow a rotating loading indicator. Blocks clicks.
onClick?(e) => voidClick handler.
paddingless?booleanDrops outer padding to zero.
ping?stringSpace-separated URLs the browser pings on navigation.
priority?primarysecondarytertiaryquaternarysecondaryVisual emphasis.
rel?stringAnchor rel.
selected?booleanToggled-on / pressed state, e.g. for filter chips.
size?smallmediumlargemediumSize variant. small=24px, medium=28px, large=32px. Omit the attribute or pass 'medium' for the default — both render identically and emit no DOM attribute.
tabIndex?number0Tab order. The button is keyboard-focusable by default (0) and becomes -1 automatically while disabled<a-button> and <a role="button"> aren't focusable without an explicit tabindex.
target?stringAnchor target.
tone?neutralbrandcriticalinfosuccesswarningstringneutralSemantic tone, or any literal CSS color ('#ff1493', 'rebeccapurple') for a one-off custom tone. Primary uses the color as-is; secondary, tertiary, and quaternary take its hue and pin lightness/chroma to the brand curve so any input stays legible.
type?buttonsubmitresetForm submission type.
underline?soliddasheddottedUnderline style.
Inherited props (children, className, id, style, title)
PropTypeDefaultDescription
children?ReactNodeChild elements. When provided, replaces the component's default label/content.
className?stringCSS class name. Merged with any internal classes by the component.
id?stringHTML id attribute.
style?CSSPropertiesInline styles applied to the root element.
title?stringHTML title attribute — native browser tooltip on hover.

Component tokens

Override any of these on a single instance (style={{ '--button-padding-x': '12px' }}) or on a selector wrapping the button (e.g. a tone or variant of your own). Color tokens are dual-declared hex; oklch; alpha fills use color-mix(in oklch, …) with a hex8 fallback first.

TokenDescription
--button-fgText and icon color. Resolved per tone × priority × state.
--button-bgBackground fill.
--button-focusFocus-ring outline color.
--button-padding-x
--button-padding-y
Inner spacing.
--button-timing-in
--button-timing-out
--button-timing-active
Per-state transitions — hover-in 75ms ease-in, return-to-rest 150ms ease-out, press 50ms linear. Quaternary zeroes all three.
--button-loading-durationOne slide cycle for the loading stripe (default 0.5s).
--button-loading-angleStripe angle (default 125deg).
--button-loading-periodStripe + gap along the gradient axis (default 30px).
--button-loading-stripe
--button-loading-stripe-gap
Stripe geometry (default 14px / 16px).
--button-loading-opacityOverlay opacity (default 0.25).
--button-loading-blurStripe-edge softening (default 2.5px).