Button takes the same props as Ant Design v6's Button, with four additions: a squircle value on shape, palettes from your theme on color (like emerald or the gray slate), an avatar prop that puts a face in the icon slot, and a loading spinner from the active icon pack. Every other prop works as it does in Ant Design.
Install
The component is copied into your project as a file you own. Run init once per project first: it installs the theme tokens and <AntuikitProvider>, and sets up the CSS layer order your class overrides depend on.
npx antuikit@latest init
npx antuikit@latest add button
Button installs on its own: the corner-squircle class it uses ships with it. Run init first anyway, since that sets up the theme.
Import
A registry:ui file lands under your ui alias, so the default path is @/components/ui/button.
Two exports come with it. ButtonProps is the props type, with shape and color widened, and buttonVariants is the cva the component composes with, for call sites that want the shape classes without the component.
import { Button, buttonVariants, type ButtonProps } from "@/components/ui/button"
color + variant
These two are the API. color says which hue, variant says how loudly, and together they reach every combination.
Write color and variant together. A variant with no color renders as a default outlined button, except solid, unless a ConfigProvider supplies both.
The type shorthand
type is the older spelling of the same axis: it reaches five fixed pairs, where color + variant reaches all of them. Both still work.
type="primary" -> color="primary" variant="solid"
type="dashed" -> variant="dashed"
type="text" -> variant="text"
type="link" -> variant="link"
type="default" -> variant="outlined"
danger is the older boolean form of color="danger". It is dropped as soon as you set color and variant, and on its own it only gives an outlined button, so write the pair.
{/* Legacy: one button, and the variant is not yours to pick */}
color takes default, primary and danger, antd's presets (blue, green, gold and the rest), or a palette from your theme (the default theme adds amber, emerald, teal, sky, indigo, violet, fuchsia, rose and grays like slate and zinc). Each works with every variant.
A palette works by name, like a preset. Besides the eight hues above, the default theme adds nine grays: slate, gray, zinc, neutral, stone, mauve, olive, mist and taupe.
Add your own in the token file the theme is generated from, under palettes, and it works by name with nothing else to wire.
{
"palettes": {
"brand": "#006bff"
}
}
A name with no palette behind it renders an ordinary gray button rather than throwing, and so does a raw hex. For an arbitrary color, use style={{ backgroundColor }}.
The neutral palettes work, but white text on their middle shade fails contrast on a solid button. Use color='default' for a gray button.
middle is v5's name for medium and still resolves, so old call sites keep working. New ones should write medium. Size can also come from <ConfigProvider componentSize>, and the avatar face and the squircle corner follow it too.
Shape
One prop, four shapes, one at a time.
default: antd's borderRadius box
squircle: a superellipse corner, added by the kit
round: a full pill
circle: a 50% radius and a square box, for icon-only
squircle needs a recent Chromium. Other browsers draw the default corner, so never let it be the only thing telling two buttons apart. Its radius is larger than the default one, because a squircle corner looks smaller at the same radius.
There is a fifth value, square, which draws the same as default.
For a rounded-square icon button, use shape="circle" with the corner-squircle class:
Icons come from the kit's Icon by semantic role rather than from an icon library by name, so swapping packs changes every glyph at once with nothing edited. Icon is 1em and aria-hidden by default, so it scales with the label and is not announced twice.
iconPlacement is start | end and logical, so it mirrors under dir="rtl" on its own. Use it rather than iconPosition, which is deprecated and warns at runtime. <AntuikitProvider> sets the gap between glyph and label through button.classNames.icon, so both placements look even.
Icon-only
An icon with no children gives an icon-only button: a square box of the control height, or a circle with shape="circle". These need an aria-label, because there is no text for the accessible name to come from.
<Button
color="default"
variant="outlined"
icon={<Icon name="more" />}
aria-label="More actions"
/>
Avatar
avatar takes an image URL and renders it as the button's face. It sizes the image from the button and keeps the same gap to the edge, the top and the bottom at every size and shape, where an image in icon sits too far from the edge.
defaultBgDisabled and dashedBgDisabled set the disabled background of default and dashed buttons. Pass var(--ant-*) values so one setting works in light and dark mode. Solid buttons read another token.
1
import { ThemeScope } from "@/components/theme-scope"
Put ghost buttons on a contrasting surface. ghost keeps the border and text color, so use it over a photo or a dark panel, not a primary background. A ghost solid button renders as outlined.
Block
block makes the button fill its parent's width: the mobile-sheet and form-footer case.
Give a Button an href and it renders an <a> instead of a <button>, with the same look. variant="link" sets the look and href sets the element, and each works without the other.
Space.Compact joins adjacent controls by context rather than by wrapping them, so each half keeps its own props. Button.Group and Dropdown.Button are deprecated, and the kit does not include Button.Group.
One primary button plus n secondary ones, and past three operations the extras fold into a Dropdown. That keeps the primary action one click away while the rest stay one click deeper.
classNames and styles are objects keyed by part, and both also accept a function returning that object. Your classNames.icon is merged with the icon class AntuikitProvider sets, so the gap to the label stays even.
Keep the border on a gradient button. Use border-transparent with a gradient background: border-none removes the border box, so the button shrinks by the border width.
Provider-level settings
Two things that look like Button props but are not. The click ripple is a ConfigProvider concern, and so is a default color/variant pair for a whole region.
For a differently themed region, use ThemeScope. A nested ConfigProvider re-themes antd's components but not the plain elements beside them, and ThemeScope themes both. It takes one theme per mode.
import { ThemeScope } from "@/components/theme-scope"