Button
Versatile action element supporting links, loading states, and icon-only mode.
Examples
Section titled “Examples”Primary
Section titled “Primary”<Button label="Button" variant="primary" />Secondary
Section titled “Secondary”<Button label="Button" variant="secondary" /><Button label="Button" variant="ghost" />Destructive
Section titled “Destructive”<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>Size Alignment
Section titled “Size Alignment”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> );}With Content
Section titled “With Content”Settings
<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>Icon Sizes
Section titled “Icon Sizes”<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>Disabled
Section titled “Disabled”This action is currently unavailable.
<Button label="Disabled" isDisabled tooltip="This action is currently unavailable."/>Loading
Section titled “Loading”<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>Loading With End Content
Section titled “Loading With End Content”<Button endContent={<Icon icon={Inbox} />} isLoading label="Sync inbox" variant="primary"/>Link Button
Section titled “Link Button”<Button label="Open docs" href="/docs" variant="primary" />With Tooltip
Section titled “With Tooltip”Helpful context for this action.
<Button label="Hover me" tooltip="Helpful context for this action." />Disabled With Tooltip
Section titled “Disabled With Tooltip”This action is not available for your current role.
<Button label="Unavailable" isDisabled tooltip="This action is not available for your current role."/>With Start Content
Section titled “With Start Content”<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>On Solid
Section titled “On Solid”Settings
<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>Icon Only Loading
Section titled “Icon Only Loading”Refresh
Refresh
Refresh
<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>Button
Section titled “Button”When isIconOnly: true
| Prop | Type | Default | Description |
|---|---|---|---|
aria-controls | string | — | 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-describedby | string | — | Identifies the element(s) that describe the button. |
aria-details | string | — | Identifies the element that provides a detailed description. |
aria-expanded | boolean | — | Indicates whether a controlled element is expanded or collapsed. |
aria-haspopup | boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | — | Indicates the button opens an interactive popup element. |
aria-hidden | boolean | — | Indicates whether the element is exposed to the accessibility API. |
aria-keyshortcuts | string | — | Keyboard shortcuts that activate or focus the button. |
aria-label | string | — | 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-labelledby | string | — | Identifies the element(s) that label the button. |
aria-owns | string | — | Identifies element(s) owned by the button that are not DOM children. |
aria-pressed | boolean | 'mixed' | — | Indicates the current pressed state of a toggle button. |
aria-roledescription | string | — | Human-readable description of the role of the button. |
as | LinkComponent | — | Custom link component to render when href is set. Falls back to the component provided by LinkProvider, or a plain <a> tag. |
className | string | — | Additional CSS class names applied to the root element. |
data-testid | string | — | Test ID applied to the root element. |
endContent | ReactNode | — | Content rendered after the label, such as a badge or count. Hidden in icon-only mode. |
form | string | — | HTML form attribute associating the button with a <form> by ID. |
href | string | — | URL to navigate to. When set and the button is not isDisabled, the component renders as a link element. |
isDisabled | boolean | — | Whether the button is disabled. Prevents interaction and applies disabled styling. |
isLoading | boolean | — | 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. |
name | string | — | HTML name attribute for form submission. |
onClick | MouseEventHandler<HTMLElement> | — | Click event handler. |
onKeyDown | (event: KeyboardEvent<HTMLElement>) => void | — | Keyboard event handler for the root element. |
ref | Ref<HTMLElement> | — | Ref forwarded to the root element. |
rel | string | — | Link rel attribute (e.g., "noopener"). Only applies when rendering as a link. |
size | "sm" | "md" | "lg" | — | Visual size of the button. |
startContent | ReactNode | — | Arbitrary content rendered before the label (after the icon, if present). Hidden in icon-only mode. |
style | CSSProperties | — | Inline styles applied to the root element. |
target | string | — | Link target attribute (e.g., "_blank"). Only applies when rendering as a link. |
tooltip | string | — | 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. |
value | string | — | HTML value attribute for form submission. |
variant | "destructive" | "primary" | "ghost" | "onSolid" | "secondary" | — | Visual style variant. |
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
| Prop | Type | Default | Description |
|---|---|---|---|
aria-controls | string | — | 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-describedby | string | — | Identifies the element(s) that describe the button. |
aria-details | string | — | Identifies the element that provides a detailed description. |
aria-expanded | boolean | — | Indicates whether a controlled element is expanded or collapsed. |
aria-haspopup | boolean | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | — | Indicates the button opens an interactive popup element. |
aria-hidden | boolean | — | Indicates whether the element is exposed to the accessibility API. |
aria-keyshortcuts | string | — | Keyboard shortcuts that activate or focus the button. |
aria-label | string | — | 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-labelledby | string | — | Identifies the element(s) that label the button. |
aria-owns | string | — | Identifies element(s) owned by the button that are not DOM children. |
aria-pressed | boolean | 'mixed' | — | Indicates the current pressed state of a toggle button. |
aria-roledescription | string | — | Human-readable description of the role of the button. |
as | LinkComponent | — | Custom link component to render when href is set. Falls back to the component provided by LinkProvider, or a plain <a> tag. |
className | string | — | Additional CSS class names applied to the root element. |
data-testid | string | — | Test ID applied to the root element. |
endContent | ReactNode | — | Content rendered after the label, such as a badge or count. Hidden in icon-only mode. |
form | string | — | HTML form attribute associating the button with a <form> by ID. |
href | string | — | URL to navigate to. When set and the button is not isDisabled, the component renders as a link element. |
isDisabled | boolean | — | Whether the button is disabled. Prevents interaction and applies disabled styling. |
isLoading | boolean | — | 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. |
name | string | — | HTML name attribute for form submission. |
onClick | MouseEventHandler<HTMLElement> | — | Click event handler. |
onKeyDown | (event: KeyboardEvent<HTMLElement>) => void | — | Keyboard event handler for the root element. |
ref | Ref<HTMLElement> | — | Ref forwarded to the root element. |
rel | string | — | Link rel attribute (e.g., "noopener"). Only applies when rendering as a link. |
size | "sm" | "md" | "lg" | — | Visual size of the button. |
startContent | ReactNode | — | Arbitrary content rendered before the label (after the icon, if present). Hidden in icon-only mode. |
style | CSSProperties | — | Inline styles applied to the root element. |
target | string | — | Link target attribute (e.g., "_blank"). Only applies when rendering as a link. |
tooltip | string | — | 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. |
value | string | — | HTML value attribute for form submission. |
variant | "destructive" | "primary" | "ghost" | "onSolid" | "secondary" | — | Visual style variant. |
icon | IconComponent | — | Icon element rendered before the label. |
isIconOnly | false | — | Visually hides the label, showing only the icon. The label prop is still required and used as aria-label. |