Actions
Button
A familiar native button for one immediate action.
When to use it: Use it to save, delete, open, or submit—not to change pages.
Example
import { useState } from "react";
import { Button } from "@comp0/react";
export function Example() {
const [saved, setSaved] = useState(false);
return (
<Button
className="rounded bg-teal-700 px-3 py-2.5 text-base text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-teal-600 sm:py-2 sm:text-sm dark:bg-teal-400 dark:text-zinc-950"
onClick={() => setSaved(true)}
>
{saved ? "Saved" : "Save changes"}
</Button>
);
}Icon button with tooltip
Name an icon-only button directly, then add a tooltip that reveals the same action on hover or focus.
import { Fragment, useState } from "react";
import { Button, Tooltip, TooltipArrow, TooltipPopover, TooltipTrigger } from "@comp0/react";
export function Example() {
const [saved, setSaved] = useState(false);
return (
<div className="flex flex-col items-center gap-2">
<Tooltip>
<TooltipTrigger as={Fragment}>
<Button
aria-label="Save draft"
className="select-none rounded-full bg-teal-700 p-2.5 text-white outline-teal-600 hover:bg-teal-800 focus-visible:outline-2 focus-visible:outline-offset-2 dark:bg-teal-400 dark:text-zinc-950 dark:outline-teal-400 dark:hover:bg-teal-300"
onClick={() => setSaved(true)}
>
<svg
aria-hidden="true"
className="size-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth="1.75"
>
<path d="M5 4h11l3 3v13H5V4Zm3 0v6h8V4M8 20v-6h8v6" />
</svg>
</Button>
</TooltipTrigger>
<TooltipPopover
placement="top"
offset={6}
className="w-max translate-y-0 overflow-visible rounded border-0 bg-zinc-900 px-2 py-1 text-sm text-white opacity-100 shadow-lg transition-[opacity,translate] duration-150 starting:translate-y-1 starting:opacity-0 motion-reduce:transition-none dark:bg-zinc-100 dark:text-zinc-900"
>
Save draft
<TooltipArrow className="absolute -bottom-1 left-1/2 size-2 -translate-x-1/2 rotate-45 bg-zinc-900 dark:bg-zinc-100" />
</TooltipPopover>
</Tooltip>
<output className="min-h-5 text-sm text-zinc-600 dark:text-zinc-400" aria-live="polite">
{saved ? "Draft saved." : ""}
</output>
</div>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
Button
Native button and press target. Owns a DOM element.
Step by step
- 1
Add the main part
Put Button where the action happens.
- 2
Add the supporting parts
Write a short verb such as Save.
- 3
Make the behavior clear
Connect onClick, or use type="submit" in a form.
Exampletsx <Button onClick={save}>Save</Button>;
Keyboard
- ↵
- Presses the focused button.
- Space
- Presses the focused button.
Forms and accessibility
A native Button submits a form when type="submit".
Accessibility checklist
- Use a visible verb that describes the action.
- Keep a visible focus ring.
- Use Link instead when the action changes the URL.
- Give an icon-only Button an aria-label; its Tooltip is supplementary and must not be its only accessible name.
API reference
import { Button } from "@comp0/react";Button
DOM elementNative button and press target.
| Prop | Type | Description |
|---|---|---|
onClick | (event: MouseEvent) => void | Runs the action on press. |
type | "button" | "submit" | "reset" | Native button type; defaults to "button". |
disabled | boolean | Disables the button; pending also disables it. |
pending | boolean | Marks a busy action: disables the button and sets aria-busy. |
as | ElementType | Renders another element with button semantics restored. |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
Button
| Style hook | Meaning |
|---|---|
[data-disabled] | The button is disabled. |
[data-pending] | The action is busy. |
[data-pressed] | The button is being pressed. |
[data-hovered] | A non-touch pointer is over it. |
[data-focused] | The button has focus. |
[data-focus-visible] | Focus should show a visible ring. |