Skip to content

Button

Versatile action element supporting links, loading states, and icon-only mode.

<Button label="Button" variant="primary" />
<Button label="Your Privacy Choices" variant="outline" />
<Button label="Button" variant="secondary" />
<Button label="Button" variant="ghost" />
<Button label="Button" variant="destructive" />
<div style={{display: 'flex', gap: '1rem', alignItems: 'center'}}>
<Button label="Small" size="sm" />
<Button label="Medium" size="md" />
<Button label="Large" size="lg" />
</div>
function SizeAlignmentStory() {
const [value, setValue] = useState('day');
const [name, setName] = useState('');
return (
<div style={{display: 'grid', gap: '1.5rem'}}>
{(['sm', 'md', 'lg'] as const).map(size => (
<div
key={size}
style={{display: 'flex', gap: '1rem', alignItems: 'center'}}>
<Button label={size} size={size} variant="primary" />
<TextInput
isLabelHidden
label={`Name (${size})`}
onChange={setName}
placeholder="Name"
size={size}
value={name}
/>
<SegmentedControl
label={`View (${size})`}
onChange={setValue}
size={size}
value={value}>
<SegmentedControlItem label="Day" value="day" />
<SegmentedControlItem label="Week" value="week" />
</SegmentedControl>
</div>
))}
</div>
);
}
<div style={{display: 'flex', gap: '1rem', alignItems: 'center'}}>
<Button icon={Plus} label="Add" />
<Button
endContent={<Icon icon={Inbox} />}
label="Inbox"
variant="secondary"
/>
<Button icon={Settings} isIconOnly label="Settings" />
</div>
<div style={{display: 'flex', gap: '1rem', alignItems: 'center'}}>
<Button icon={Plus} label="Small" size="sm" />
<Button icon={Plus} label="Medium" size="md" />
<Button icon={Plus} label="Large" size="lg" />
</div>
<Button
label="Disabled"
isDisabled
tooltip="This action is currently unavailable."
/>
<div style={{display: 'flex', gap: '1rem', alignItems: 'center'}}>
<Button isLoading label="Small" size="sm" variant="primary" />
<Button isLoading label="Medium" size="md" variant="primary" />
<Button isLoading label="Large" size="lg" variant="primary" />
</div>
<Button
endContent={<Icon icon={Inbox} />}
isLoading
label="Sync inbox"
variant="primary"
/>
<Button label="Open docs" href="/docs" variant="primary" />
<Button label="Hover me" tooltip="Helpful context for this action." />
<Button
label="Unavailable"
isDisabled
tooltip="This action is not available for your current role."
/>
<div style={{display: 'flex', gap: '1rem', alignItems: 'center'}}>
<Button
label="Status"
startContent={
<span
className={css({
w: '2',
h: '2',
borderRadius: 'full',
bg: 'green',
})}
/>
}
/>
<Button
label="Inbox"
startContent={<Icon icon={Inbox} />}
variant="primary"
/>
<Button
endContent={<Icon icon={Settings} />}
label="Configure"
startContent={
<span
className={css({
w: '2',
h: '2',
borderRadius: 'full',
bg: 'orange',
})}
/>
}
variant="secondary"
/>
</div>
<div
className={css({bg: 'primary', borderRadius: 'lg', p: '4'})}
style={{
display: 'flex',
gap: '0.5rem',
alignItems: 'center',
color: 'white',
}}>
<Button icon={Settings} isIconOnly label="Settings" variant="onSolid" />
<Button label="Action" variant="onSolid" />
<Button icon={Plus} label="Add item" variant="onSolid" />
</div>
<VStack align="start" gap={3} width={320}>
<Button label="Intrinsic width" />
<Button label="240 pixels" variant="secondary" width={240} />
<Button label="18rem" variant="secondary" width="18rem" />
<Button label="Fills the container" variant="primary" width="full" />
</VStack>

Confirm upgrade

Stacked calls to action fill the footer without a wrapper element.

() => {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button label="Open dialog" onClick={() => setIsOpen(true)} />
<Dialog
isOpen={isOpen}
label="Confirm upgrade"
onOpenChange={setIsOpen}
width={360}>
<Layout
content={
<LayoutContent>
<Text as="p" color="secondary">
Stacked calls to action fill the footer without a wrapper
element.
</Text>
</LayoutContent>
}
footer={
<LayoutFooter>
<VStack gap={2} width="full">
<Button
label="Upgrade plan"
onClick={() => setIsOpen(false)}
variant="primary"
width="full"
/>
<Button
label="Not now"
onClick={() => setIsOpen(false)}
variant="ghost"
width="full"
/>
</VStack>
</LayoutFooter>
}
header={<LayoutHeader title="Confirm upgrade" />}
/>
</Dialog>
</>
);
}
<div style={{display: 'flex', gap: '1rem', alignItems: 'center'}}>
<Button icon={RefreshCw} isIconOnly isLoading label="Refresh" size="sm" />
<Button
icon={RefreshCw}
isIconOnly
isLoading
label="Refresh"
size="md"
variant="primary"
/>
<Button
icon={RefreshCw}
isIconOnly
isLoading
label="Refresh"
size="lg"
variant="ghost"
/>
</div>

When isIconOnly: true

PropTypeDefaultDescription
aria-controlsstring—Identifies the element(s) whose contents are controlled by the button.
aria-current'page' | 'step' | 'location' | 'date' | 'time'—Indicates the current item in a set.
aria-describedbystring—Identifies the element(s) that describe the button.
aria-detailsstring—Identifies the element that provides a detailed description.
aria-expandedboolean—Indicates whether a controlled element is expanded or collapsed.
aria-haspopupboolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'—Indicates the button opens an interactive popup element.
aria-hiddenboolean—Indicates whether the element is exposed to the accessibility API.
aria-keyshortcutsstring—Keyboard shortcuts that activate or focus the button.
aria-labelstring—Accessible label that overrides the visible label for assistive technologies. Use when the visible text is too terse (e.g. a page number) and a longer description is needed.
aria-labelledbystring—Identifies the element(s) that label the button.
aria-ownsstring—Identifies element(s) owned by the button that are not DOM children.
aria-pressedboolean | 'mixed'—Indicates the current pressed state of a toggle button.
aria-roledescriptionstring—Human-readable description of the role of the button.
asLinkComponent—Custom link component to render when href is set. Falls back to the component provided by LinkProvider, or a plain <a> tag.
classNamestring—Additional CSS class names applied to the root element.
data-testidstring—Test ID applied to the root element.
endContentReactNode—Content rendered after the label, such as a badge or count. Hidden in icon-only mode.
formstring—HTML form attribute associating the button with a <form> by ID.
hrefstring—URL to navigate to. When set and the button is not isDisabled, the component renders as a link element.
idstring—HTML id attribute applied to the root element.
isDisabledboolean—Whether the button is disabled. Prevents interaction and applies disabled styling.
isLoadingboolean—Whether the button is in a loading state. Shows a spinner overlay, disables interaction, and announces "Loading" to assistive technologies.
label*string—Text label for the button. Always required for accessibility even when isIconOnly is true.
namestring—HTML name attribute for form submission.
onClickMouseEventHandler<HTMLElement>—Click event handler.
onFocusFocusEventHandler<HTMLElement>—Focus event handler for the root element.
onKeyDown(event: KeyboardEvent<HTMLElement>) => void—Keyboard event handler for the root element.
onPointerEnterPointerEventHandler<HTMLElement>—Pointer enter event handler for the root element.
refRef<HTMLElement>—Ref forwarded to the root element.
relstring—Link rel attribute (e.g., "noopener"). Only applies when rendering as a link.
size"sm" | "md" | "lg"—Visual size of the button.
startContentReactNode—Arbitrary content rendered before the label (after the icon, if present). Hidden in icon-only mode.
styleCSSProperties—Inline styles applied to the root element.
targetstring—Link target attribute (e.g., "_blank"). Only applies when rendering as a link.
tooltipstring—Tooltip text shown on hover. Defaults to label when isIconOnly is true (since the label is otherwise not visible); pass an explicit value to override, or undefined to keep the default. When set on a disabled button, aria-disabled is used instead of the disabled attribute so the tooltip remains accessible.
type'button' | 'submit' | 'reset'—HTML button type attribute.
valuestring—HTML value attribute for form submission.
variant"destructive" | "primary" | "ghost" | "onSolid" | "outline" | "secondary"—Visual style variant.
widthWidthValue—Button width. Numbers are pixels, strings are used as-is, 'full' fills the container.
icon*IconComponent—Icon element rendered before the label. Required in icon-only mode.
isIconOnly*true—Visually hides the label, showing only the icon. The label prop is still required and used as aria-label.

When isIconOnly: false

PropTypeDefaultDescription
aria-controlsstring—Identifies the element(s) whose contents are controlled by the button.
aria-current'page' | 'step' | 'location' | 'date' | 'time'—Indicates the current item in a set.
aria-describedbystring—Identifies the element(s) that describe the button.
aria-detailsstring—Identifies the element that provides a detailed description.
aria-expandedboolean—Indicates whether a controlled element is expanded or collapsed.
aria-haspopupboolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog'—Indicates the button opens an interactive popup element.
aria-hiddenboolean—Indicates whether the element is exposed to the accessibility API.
aria-keyshortcutsstring—Keyboard shortcuts that activate or focus the button.
aria-labelstring—Accessible label that overrides the visible label for assistive technologies. Use when the visible text is too terse (e.g. a page number) and a longer description is needed.
aria-labelledbystring—Identifies the element(s) that label the button.
aria-ownsstring—Identifies element(s) owned by the button that are not DOM children.
aria-pressedboolean | 'mixed'—Indicates the current pressed state of a toggle button.
aria-roledescriptionstring—Human-readable description of the role of the button.
asLinkComponent—Custom link component to render when href is set. Falls back to the component provided by LinkProvider, or a plain <a> tag.
classNamestring—Additional CSS class names applied to the root element.
data-testidstring—Test ID applied to the root element.
endContentReactNode—Content rendered after the label, such as a badge or count. Hidden in icon-only mode.
formstring—HTML form attribute associating the button with a <form> by ID.
hrefstring—URL to navigate to. When set and the button is not isDisabled, the component renders as a link element.
idstring—HTML id attribute applied to the root element.
isDisabledboolean—Whether the button is disabled. Prevents interaction and applies disabled styling.
isLoadingboolean—Whether the button is in a loading state. Shows a spinner overlay, disables interaction, and announces "Loading" to assistive technologies.
label*string—Text label for the button. Always required for accessibility even when isIconOnly is true.
namestring—HTML name attribute for form submission.
onClickMouseEventHandler<HTMLElement>—Click event handler.
onFocusFocusEventHandler<HTMLElement>—Focus event handler for the root element.
onKeyDown(event: KeyboardEvent<HTMLElement>) => void—Keyboard event handler for the root element.
onPointerEnterPointerEventHandler<HTMLElement>—Pointer enter event handler for the root element.
refRef<HTMLElement>—Ref forwarded to the root element.
relstring—Link rel attribute (e.g., "noopener"). Only applies when rendering as a link.
size"sm" | "md" | "lg"—Visual size of the button.
startContentReactNode—Arbitrary content rendered before the label (after the icon, if present). Hidden in icon-only mode.
styleCSSProperties—Inline styles applied to the root element.
targetstring—Link target attribute (e.g., "_blank"). Only applies when rendering as a link.
tooltipstring—Tooltip text shown on hover. Defaults to label when isIconOnly is true (since the label is otherwise not visible); pass an explicit value to override, or undefined to keep the default. When set on a disabled button, aria-disabled is used instead of the disabled attribute so the tooltip remains accessible.
type'button' | 'submit' | 'reset'—HTML button type attribute.
valuestring—HTML value attribute for form submission.
variant"destructive" | "primary" | "ghost" | "onSolid" | "outline" | "secondary"—Visual style variant.
widthWidthValue—Button width. Numbers are pixels, strings are used as-is, 'full' fills the container.
iconIconComponent—Icon element rendered before the label.
isIconOnlyfalse—Visually hides the label, showing only the icon. The label prop is still required and used as aria-label.