Button
A Button component that handles variant stylings and states
- 6 variant styles for each use case.
- 3 sizes
sm, md, lgfollowing same spacing design-system. - Builtin left/right icon placement.
- Builtin spinner and internal loading state.
- Builtin optional tooltip.
Import
import { Button } from "h2o-library";Usage
Variants
<Button label="Primary" />
<Button variant="secondary" label="Secondary" />
<Button variant="ghost" label="Ghost" />
<Button variant="danger" label="Danger" />
<Button variant="warning" label="Warning" />
<Button variant="success" label="Success" />
Sizes
Icon Placement
Icons can go on the right (default) or left via iconPosition.
<Button icon="download" label="Download" />
<Button icon="plus" label="Add item" iconPosition="left" />
Icon Only
Always pair with tooltip — it will be used as the accessible aria-label automatically.
<Button variant="primary" icon="plus" iconOnly tooltip="Add new item" />;Loading State
isLoading disables the button and replaces content with a spinner. Setting aria-busy is handled automatically.
<Button label="Saving…" isLoading />;Full Width
<Button label="Submit form" fullWidth />;Disabled
Playground
Loading playground…
Usage in Forms
Uncontrolled submit
<form
onSubmit={(e) => {
e.preventDefault(); /* handle */
}}
>
<Input name="email" placeholder="Email" />
<Button type="submit" label="Subscribe" />
</form>;Controlled with useState
const [loading, setLoading] = useState(false);
async function handleSubmit() {
setLoading(true);
await submitData();
setLoading(false);
}
<Button
label={loading ? "Saving…" : "Save"}
isLoading={loading}
onClick={handleSubmit}
/>;With react-hook-form
import { useForm } from "react-hook-form";
function LoginForm() {
const {
handleSubmit,
formState: { isSubmitting },
} = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* fields */}
<Button
type="submit"
label={isSubmitting ? "Signing in…" : "Sign in"}
isLoading={isSubmitting}
fullWidth
/>
</form>
);
}Keyboard
Native <button> behavior:
| Key | Action |
|---|---|
Enter / Space | Activates the button (does not submit a form unless type="submit"). |
Tab / Shift+Tab | Move focus. |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Button text. Can be replaced by children. |
variant | "primary" | "secondary" | "ghost" | "danger" | "warning" | "success" | "primary" | Visual style of the button. |
size | "sm" | "md" | "lg" | "md" | Height and font size of the button. |
icon | IconType | undefined | Icon name from the icon set. |
iconPosition | "left" | "right" | "right" | Side of the label where the icon is placed. |
iconOnly | boolean | false | Renders only the icon. Pair with tooltip for accessibility. |
iconStrokeWidth | number | 1.5 | Stroke width passed to the Icon component. |
isLoading | boolean | false | Shows a spinner, sets aria-busy, and disables the button. |
fullWidth | boolean | false | Stretches the button to fill its container. |
disabled | boolean | false | Disables the button. |
tooltip | string | undefined | Tooltip shown on hover. Also used as aria-label for iconOnly. |
tooltipPosition | "top" | "bottom" | "left" | "right" | "top" | Position of the tooltip. |
className | string | "" | Additional CSS classes. |
Extends all native <button> HTML attributes.
Design Guidelines
- Use
primaryfor the single main action on a page or in a form. - Use
secondaryfor alternative or cancel actions. - Use
ghostfor low-emphasis actions in toolbars or dense UI. - Use
dangerfor destructive actions (delete, remove, revoke). - Always provide
tooltipwhen usingiconOnly— it doubles as the accessible label.
Accessibility
- Buttons are keyboard accessible and triggered with
EnterorSpace. iconOnlybuttons derivearia-labelfromtooltipautomatically.isLoadingsetsaria-busy="true"and disables the button to prevent double-submission.