Skip to content

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.

On this page

Example

Loading example…
Button.tsxtsx
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.

Loading example…
button.icon-tooltip.tsxtsx
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.

  1. Button

    Native button and press target. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Put Button where the action happens.

  2. 2

    Add the supporting parts

    Write a short verb such as Save.

  3. 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

Importtsx
import { Button } from "@comp0/react";

Button

DOM element

Native button and press target.

PropTypeDescription
onClick(event: MouseEvent) => voidRuns the action on press.
type"button" | "submit" | "reset"Native button type; defaults to "button".
disabledbooleanDisables the button; pending also disables it.
pendingbooleanMarks a busy action: disables the button and sets aria-busy.
asElementTypeRenders 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 hookMeaning
[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.

Keep exploring