Use buttons to initiate actions and communicate their importance through labels, roles, and visual treatments.
A button initiates an action in the current interface. Use it for operations such as saving changes, opening a dialog, or applying a setting. Give the action a label that describes its result.
Use a Link with an href when the primary purpose is to navigate to another destination. Without an href, Link can render an action control instead. Choose a value control, such as Toggle, when the interface represents a persistent setting.
Carbon describes emphasis with names such as primary, secondary, tertiary, and ghost, and uses danger for destructive actions. These are not Liquidify variant names. In Liquidify, choose a visual variant separately from the action's role; a prominent variant expresses emphasis without assigning a primary role.
Apple distinguishes a button's style, content, and role. SwiftUI applies styles through modifiers and can adapt buttons to their container. Liquidify exports a React Button with explicit props. Its only action roles are destructive and cancel; omit the role for an ordinary action. These values describe action intent through Liquidify's styling; they do not replace the rendered element's native accessibility role or announce the consequence on their own. A role does not perform deletion, cancellation, navigation, or dismissal. Supply that behavior in application code.
A Liquidify Button can contain a text label, a leading icon, a trailing icon, or an icon with an accessible name. Its surface communicates visual emphasis; its role describes the action's purpose.


Keep the label readable and the surrounding space sufficient to distinguish the control from nearby actions. Review long labels in the actual layout rather than relying on a short demonstration label.
The installed Button API provides eight variants. Choose one according to the action's importance and the surface behind it.
| Variant | Treatment and appropriate use |
|---|---|
automatic | The default outside a ControlGroup. An unfilled treatment for an action that needs little surface emphasis. |
plain | An unfilled treatment with the default foreground color, useful for supporting actions. |
bordered | A glass capsule that gives an action a visible boundary without a prominent fill. |
borderedProminent | A filled treatment for the main action in a group. |
borderless | An explicit unfilled treatment; the shipped stylesheet gives it the same appearance as automatic. |
glass | A glass capsule with activation motion, suitable where separation from the background helps identify the control. |
glassProminent | A prominent filled glass treatment with activation motion. |
translucent | A partially transparent tinted capsule. Review its label against the actual backdrop. This is a Liquidify option without a direct SwiftUI button-style counterpart. |
An omitted variant becomes plain inside a ControlGroup. The group can also supply size, tint, and disabled state. This documented context does not imply SwiftUI-style adaptation to arbitrary parent containers.


Use a prominent treatment when an action needs greater emphasis. Use quieter treatments for supporting actions. Keep related actions at a consistent size and vary their treatment to express priority. The best choice depends on the surrounding content and the other controls that appear with it.
Button supports small, regular, and large sizes, with regular as the default outside a group. Choose a size that fits the surrounding controls and input method. Do not use size alone to indicate the preferred action or copy native platform point measurements into CSS.
Use tint for a supported accent choice and role for destructive or cancellation intent. The rendered color depends on the variant as well as these props. For a destructive action, start with variant="bordered" or variant="borderedProminent", role="destructive", and no explicit or inherited tint. The shipped stylesheet does not preserve destructive coloring consistently across every variant/tint combination. Always name the consequence in the label and check the rendered result.
Use onPress for the primary action. It receives no event argument and runs after an enabled, non-loading button is activated, unless its onClick handler calls preventDefault(). Use onClick when the handler needs the React click event. Avoid starting the same operation in both callbacks: a single activation can call both. The application remains responsible for the operation and its outcome.
aria-busy, and suppresses activation. It remains focusable unless it is also disabled.

The comparison uses the same borderedProminent button in each state. Keyboard focus is independent of loading: a loading button can retain focus while its action is suppressed.
The application must set and clear loading; onPress does not await a returned promise or manage errors. Keep outcome and failure feedback near the task. Preserve an informative label while waiting, such as “Saving changes,” and restore an available action when recovery is possible. A spinner indicates progress, not success.
The default native button is the starting point for actions. If a destination needs button appearance, use as="a" with href; it remains a link with native link keyboard behavior. A disabled anchor receives aria-disabled and suppresses click activation, but remains in the tab order. Loading also suppresses click activation. Neither state removes the destination from the anchor, so do not use these states as access control.
Use asChild only when integrating a single semantic element that must own the rendered root. The child must forward the supplied attributes, event handlers, and ref. Its props can override merged attributes, so verify the final accessible name and disabled behavior. Button does not add its content wrapper, icon slots, or spinner in this mode; supply the child's content and progress feedback yourself. Do not use a generic element and assume it gains native button keyboard behavior.
Start with the action people will take, such as “Save changes” or “Add account.” Keep labels concise while preserving enough context to predict the result.
Use familiar icons when they clarify an action. An icon-only button needs an explicit accessible name. A tooltip can provide additional visible context, but Button does not create one automatically and a tooltip should not replace its accessible name. Avoid using an unfamiliar icon as the only explanation of a consequential operation.
The default Button renders a native button with type="button". Set type="submit" deliberately when it submits a form; handle the submission in the form rather than also saving in onPress. People can focus it with Tab and activate it with Enter or Space. Preserve a visible focus indicator and avoid placing another interactive element inside it.
A disabled button can communicate that an action is unavailable, but it does not explain why. Provide that explanation in nearby content when the condition is not clear. See Disabled states for choosing between unavailable, waiting, and read-only presentations.
Review keyboard focus, long labels, enlarged text, and touch operation in the actual layout. The shipped CSS reduces Button motion when prefers-reduced-motion: reduce is active; the application still needs to review any motion or feedback it adds.
Start with variant, size, tint, and the icon slots. Button exposes no material, perf, or inline style prop. Use page-owned classes for layout and documented public tokens for shared visual decisions; avoid selecting private label or spinner elements.
For example, choose tint="accent" on a prominent variant when it should follow --lq-color-accent. A named tint such as blue selects a system color instead. Check the chosen variant in both themes rather than assuming every treatment consumes tint in the same way. See Color for semantic roles and contrast review.
Use the Button catalog for imports, props, and interactive examples. Read Dialogs when an action requires a focused decision before execution.