Skip to content

ActionsIcon button

Icon button

A square, icon-only button. Used for compact toolbars, table actions, and the close button on overlays.

1 required label3 sizes3 variants

Demo

The default is a 36 × 36 px ghost button. The label is announced by assistive tech; the icon is decorative.

Default

Sizes

Sizes

Variants

Variants

Implementation

icon-button.tsx
import { forwardRef, type ButtonHTMLAttributes } from "react"
import SiteIcon, type SiteIconProps } from "@/components/site-icon"

interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  icon: SiteIconProps["icon"]
  label: string
  size?: "sm" | "md" | "lg"
  variant?: "primary" | "secondary" | "ghost"
}

export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
  function IconButton({ icon, label, size = "md", variant = "ghost", className, ...props }, ref) {
    return (
      <button
        ref={ref}
        aria-label={label}
        className={cn("ds-icon-btn", `ds-icon-btn--${size}`, `ds-icon-btn--${variant}`, className)}
        {...props}
      >
        <SiteIcon icon={icon} size={size === "lg" ? "md" : "sm"} aria-hidden />
      </button>
    )
  },
)

Props

PropTypeDefaultDescription
iconLucideIconNoneThe icon
labelstringNoneRequired: the accessible label
size"sm" | "md" | "lg""md"Touch target
variant"primary" | "secondary" | "ghost""ghost"Visual style

Accessibility

  • The aria-label prop is required. There is no fallback label.
  • The icon is marked aria-hidden; the label is the only thing announced.
  • Touch target is at least 32 × 32 px. The default is 36 × 36 px.
  • Focus ring is the system default.