packages/react-components/react-button/library/docs/SPEC.md
GitHub Epic issue - Button Convergence #16746
The Button component enables users to trigger an action or event, such as submitting a form, opening a dialog, canceling an action, or performing a delete operation.
The Open UI Button Research page, shows how the Button component is used in UI platforms across the web. While there is consensus about some of the basic features that the Button needs to support the more advanced features and the variants presented differ significantly among the different UI platforms.
The existing components are:
Basic examples:
<Button>Text</Button>
<Button icon={<SVGIcon />} />
<Button icon={<SVGIcon />}>Text</Button>
<Button icon={<SVGIcon />} iconPosition="after">Text</Button>
<Button appearance="primary">Text</Button>
<Button disabled>Text</Button>
<Button size="small">Text</Button>
<Button size="large">Text</Button>
The Button component has several apparance variants depending on where it's being used:
Button is rendered with its default styling indicating a trigger for an action.Button is styled such that it has no background styling and is just emphasized through the styling of its content and borders.Button is styled to emphasize that it represents the primary action.Button is styled to blend into its background to become less emphasized.Button is styled such that it has no background or border styling and is just emphasized through its content styling.The Button component can include an icon that appears before or after its children. If an icon is provided without any children, then the Button becomes an icon-only Button.
The Button component supports different sizing with at least three different sizes: small, medium (default) and large.
root - The outer container representing the Button itself that wraps everything passed via the children prop.icon - If specified, renders an icon either before or after the children as specified by the iconPosition prop.See API at Button.types.ts.
For Buttons rendering as <button>:
Icon before children:
<button class="root" href={href}>
<span class="icon" />
{children}
</button>
Icon after children:
<button class="root" href={href}>
{children}
<span class="icon" />
</button>
For Buttons rendering as anything other than <button> (the example below uses <div>):
<div class="root" href={href}>
<span class="icon" />
{children}
</div>
Icon after children:
<div class="root" href={href}>
{children}
<span class="icon" />
</div>
See MIGRATION.md.
The following section describes the different states in which a Button can be throughout the course of interaction with it.
An enabled Button communicates interaction by having styling that invites the user to click/tap on it to trigger an action.
A disabled Button is non-interactive, disallowing the user to click/tap on it to trigger an action.
A hovered Button changes styling to communicate that the user has placed a cursor above it.
A focused Button changes styling to communicate that the user has placed keyboard focus on it. This styling is usually the same to the one in the hovered state plus extra styling on the outline to indicate keyboard focus has been placed on the component.
A pressed Button changes styling to communicate that the user is currently pressing it.
The following is a set of keys that interact with the Button component:
| Key | Description |
|---|---|
Enter | Executes the Button action. |
Space | Executes the Button action. |
Shift + F10 (Optional) | Opens a context menu for the Button. |
mouseenter: Should immediately change the styling of the Button so that it appears to be hovered.mouseleave: Should immediately remove the hovered styling of the Button.mouseup: If triggered while cursor is still inside of the Button's boundaries, then it should execute the Button and move focus to its target.The same behavior as above translated for touch events. This means that there is no equivalent for mouseenter and mouseleave, which makes it so that the hovered state cannot be accessed.
button element unless something else has been specified for the root slot, in which case role="button" should be added to it.button native element.