IconButton

A square button for one icon.

Overview

An action with a familiar icon and no room for a word: delete, settings, alerts.

Label

Do
import { IconButton } from "@hackcove/ui";

<IconButton label="Delete quote" tone="danger" variant="ghost">
  <svg
    viewBox="0 0 24 24"
    width="16"
    height="16"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    aria-hidden="true"
  >
    <path d="M6 6l12 12M18 6L6 18" />
  </svg>
</IconButton>
label names the button for a screen reader and shows as its tooltip; the icon is only decoration.
Don't
import { Button } from "@hackcove/ui";

<Button variant="ghost" tone="danger" size="sm">
  <span aria-hidden="true">x</span>
</Button>
A Button holding a glyph has no accessible name, no tooltip and the wrong box; an icon-only action is an IconButton.

Badge

Do
import { IconButton } from "@hackcove/ui";

<IconButton label="Alerts" badge={3}>
  <svg
    viewBox="0 0 24 24"
    width="16"
    height="16"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
    aria-hidden="true"
  >
    <path d="M18 16v-5a6 6 0 1 0-12 0v5l-2 2h16l-2-2ZM10 21h4" />
  </svg>
</IconButton>
badge pins the count to the corner and adds it to the accessible name ("Alerts, 3").
Don't
import { IconButton } from "@hackcove/ui";

<IconButton label="Alerts (3)">
  <svg
    viewBox="0 0 24 24"
    width="16"
    height="16"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    strokeLinejoin="round"
    aria-hidden="true"
  >
    <path d="M18 16v-5a6 6 0 1 0-12 0v5l-2 2h16l-2-2ZM10 21h4" />
  </svg>
</IconButton>
A count typed into the label shows only in the tooltip, so a sighted user never sees it on the button.

Navigate

Do
import { IconButton } from "@hackcove/ui";

<IconButton href="#settings" label="Settings" variant="ghost">
  <svg
    viewBox="0 0 24 24"
    width="16"
    height="16"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    aria-hidden="true"
  >
    <path d="M4 8h10M18 8h2M4 16h2M10 16h10" />
    <circle cx="16" cy="8" r="2" />
    <circle cx="8" cy="16" r="2" />
  </svg>
</IconButton>
Going to another page is href: the same look on a real anchor, with middle-click and the URL.
Don't
import { IconButton } from "@hackcove/ui";

<IconButton label="Settings" variant="ghost" onClick={() => location.assign("#settings")}>
  <svg
    viewBox="0 0 24 24"
    width="16"
    height="16"
    fill="none"
    stroke="currentColor"
    strokeWidth="2"
    strokeLinecap="round"
    aria-hidden="true"
  >
    <path d="M4 8h10M18 8h2M4 16h2M10 16h10" />
    <circle cx="16" cy="8" r="2" />
    <circle cx="8" cy="16" r="2" />
  </svg>
</IconButton>
A button that sets location loses middle-click, the status-bar URL and crawlability.

Usage

  • Always give the label: it is the accessible name and the tooltip, and the icon is only decoration.
  • variant="ghost" is the quiet one for a row or a toolbar; tone="danger" is for delete and clear.
  • An unread count is badge, never part of the label; it is not shown at 0.
  • Going to another page is href (or render for the app's router link), which draws the same button as a link.
  • An action that needs a word is a Button.

Accessibility

  • label is set as aria-label and title; with a badge it reads Alerts, 3.
  • The badge itself is aria-hidden, so the count is read once, through the name.
  • As a button it defaults to type="button"; with href or render it is a real link, and external opens a new tab with rel="noreferrer".
  • It has the component's focus ring.

API

IconButton

A square button holding one icon. label is its accessible name and tooltip. variant="ghost" drops the border for a quiet action in a row or a toolbar; tone="danger" is red, for delete and clear; badge pins a red count to the corner. Defaults to type="button". href makes it a link instead (a plain <a>, or with render the app's own router <Link>: render={(p) => <Link to="/settings" {...p} />}; external opens a new tab), with the same look.


badge

A red count on the top-right corner, for unread alerts. Not shown at 0; label carries it for a screen reader.

Type
number

external

Opens in a new tab: adds target="_blank" and rel="noreferrer".

Type
boolean

href
Type
string

label required
Type
string

render
Type
LinkRender

tone

danger is red, for delete and clear.

Type
"default" | "danger"
Default
default

variant

outline has a border; ghost has none, until the hover fill.

Type
"outline" | "ghost"
Default
outline