Examples
When to use
Use Button for an in-place action: saving, submitting, opening a menu, or changing a local state. Use an anchor when the primary outcome is navigation, even if the link is styled like a button.
“Save changes”, “Add teammate”, and “Try again” all change application state.
“View report” and “Open settings” take the person to another URL or route.
Usage
The copied playground code is the smallest runnable form for the selected props. A static composition with several actions looks like this:
import { Button } from "@phuctech/ui/components/button";
export function Example() {
return <Button>Save changes</Button>;
}
- Keep the label verb-led and specific. Do not make an icon carry the only meaning.
- Use
disabledwhen the action cannot be performed; explain a non-obvious reason nearby. - Use
loadingfor an in-flight action. It disables repeat activation, keeps the button size, exposesaria-busy, and uses the unavailable cursor. - Available buttons use
cursor-pointer;disabledandloadingbuttons usecursor-not-allowed. - Confirm an irreversible destructive action in a shared dialog before calling the action.
Variants and states
Icons
Use PhucTech icons from @phuctech/ui/icons. An icon next to a text label is decorative and should have aria-hidden="true". An icon-only Button needs a concise aria-label and one of the icon-* sizes.
API
Button forwards Base UI button props and adds the visual variants below. Composition uses Base UI's render prop; this API does not add an asChild alias.
All native button props, event handlers, children, and className are forwarded. The underlying element remains a native button unless render composes it.
Tokens
Accessibility
- Native keyboard activation works with Enter and Space; focus uses the shared visible ring.
- Text labels are preferred. Icon-only buttons must provide
aria-label. loadingdisables repeated activation and exposes a busy state; keep surrounding feedback for long operations.- Do not use color alone to communicate destructive or disabled intent.
Do and don’t
Use one clear primary action, keep labels specific, and test focus, disabled, and loading states with a keyboard.
Use a Button for navigation, nest interactive elements, or hide the only label inside a decorative icon.
Related
- Sizing defines control heights and touch targets.
- Accessibility documents focus and contrast contracts.
- DropdownMenu composes Button as its trigger with Base UI's
renderprop.