Talisson Costa
← All components

Icon Button

Square button for a single icon. Its accessible name is required by the type, so it can't ship unlabeled.

  • required label (types)
  • cva
  • builds on Button

label is required by the type, so an unlabeled icon button doesn't compile.

Install

npx shadcn@latest add https://tcosta.dev/r/icon-button.json

Or copy the files below into components/icon-button/. They use the shadcn/ui theme tokens and cn from @/lib/utils, and need class-variance-authority.

Source

icon-button.tsx
import type { ReactElement } from 'react';
import { cn } from '@/lib/utils';
import { Button, type ButtonProps } from '../button';
import { iconButtonVariants } from './icon-button-variants';

type IconButtonProps = Omit<ButtonProps, 'children' | 'aria-label'> & {
  /** Accessible name. Required: an icon alone says nothing to a screen reader. */
  label: string;
  children: ReactElement;
};

export function IconButton({ label, size, className, ...props }: IconButtonProps) {
  return (
    <Button
      aria-label={label}
      size={size}
      className={cn(iconButtonVariants({ size }), className)}
      {...props}
    />
  );
}
icon-button-variants.ts
import { cva } from 'class-variance-authority';

export const iconButtonVariants = cva('px-0', {
  variants: {
    size: {
      sm: 'size-8',
      md: 'size-9',
      lg: 'size-10',
    },
  },
  defaultVariants: {
    size: 'md',
  },
});
index.ts
export { IconButton } from './icon-button';
export { iconButtonVariants } from './icon-button-variants';