IconButton

ui actionicon

Quadratischer Icon-Button für Zeilen-Aktionen. Trägt IMMER ein Label — es wird zu aria-label und title, weil nur ein Glyph sichtbar ist. Tonlagen: neutral · accent (primäre Aktion) · danger (destruktiv); `pressed` macht daraus einen Toggle.

Keine interaktive Live-Demo — siehe Code & Beispiele unten.

Abhängigkeiten

Barrierefreiheit

  • Pflicht-`label` wird als aria-label UND title gesetzt — ein Icon allein ist kein Name.
  • `pressed` schaltet aria-pressed für Toggle-Aktionen (z. B. „Favorit").

Beispiele

Zeilen-Aktionen
<IconButton label="Umbenennen" onClick={rename}><RenameIcon /></IconButton>
<IconButton label="Löschen" tone="danger" onClick={remove}><TrashIcon /></IconButton>
Toggle
<IconButton label="Favorit" pressed={fav} onClick={toggle}>
  {fav ? <StarFilledIcon /> : <StarIcon />}
</IconButton>

Genutzte Tokens · 10

--accent-fg--accent-soft--ease-standard--fg--focus-ring--motion-fast--muted--radius-sm--tag-danger-fg--tag-warn-fg

Quelldateien

components/ui/IconButton.tsx tsx
import type { ReactNode } from 'react';
import styles from './IconButton.module.css';

/**
 * Quadratischer Icon-Button (aus dem mga-scores `icon-btn`-Muster, auf die
 * Familien-Tokens gehoben). Trägt IMMER ein Label — es wird als `aria-label`
 * und `title` gesetzt, weil der Button nur ein Glyph zeigt.
 *
 * `tone`: neutral (Default) · accent (primäre Aktion einer Zeile) · danger
 * (destruktiv). `pressed` schaltet `aria-pressed` (Toggle wie „Favorit").
 */
export interface IconButtonProps {
  label: string;
  children: ReactNode;
  onClick?: () => void;
  tone?: 'neutral' | 'accent' | 'danger';
  size?: 'sm' | 'md';
  pressed?: boolean;
  disabled?: boolean;
  className?: string;
}

export function IconButton({
  label,
  children,
  onClick,
  tone = 'neutral',
  size = 'md',
  pressed,
  disabled,
  className,
}: IconButtonProps) {
  const cls = [styles.btn, styles[tone], styles[size], className].filter(Boolean).join(' ');
  return (
    <button
      type="button"
      className={cls}
      aria-label={label}
      title={label}
      onClick={onClick}
      disabled={disabled}
      {...(pressed === undefined ? {} : { 'aria-pressed': pressed })}
    >
      {children}
    </button>
  );
}
components/ui/IconButton.module.css css
.btn {
  display: inline-grid;
  place-items: center;
  flex: 0 0 auto;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  font: inherit;
  transition:
    color var(--motion-fast) var(--ease-standard),
    background var(--motion-fast) var(--ease-standard),
    border-color var(--motion-fast) var(--ease-standard);
}
.btn:hover:not(:disabled) {
  color: var(--fg);
  background: color-mix(in oklab, var(--fg), transparent 92%);
}
.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}
.btn:disabled {
  opacity: 0.45;
  cursor: default;
}

.sm {
  width: 26px;
  height: 26px;
}
.md {
  width: 32px;
  height: 32px;
}

.accent {
  color: var(--accent-fg);
}
.accent:hover:not(:disabled) {
  color: var(--accent-fg);
  background: var(--accent-soft);
}

.danger:hover:not(:disabled) {
  color: var(--tag-danger-fg);
  background: color-mix(in oklab, var(--tag-danger-fg), transparent 90%);
}

/* Aktiver Toggle (z. B. gesetzter Favorit). */
.btn[aria-pressed='true'] {
  color: var(--tag-warn-fg);
}

Holen

# MCP (Claude Code / Cursor)
get_component({ name: "icon-button" })

# Registry direkt
https://www.ekklesi.tools/design/registry/components/icon-button.json