# Composition — Icons

Icons clarify intent, anchor scanning, and shorten labels. They never replace a label on an interactive control unless that control is an `IconButton` with an explicit accessible name.

## Where icons appear

| Position | Pattern | Components |
|---|---|---|
| **Leading** (before text) | Cue what the input or action is for | `TextField`, `Search`, `Button`, `Link`, `MenuButton`, `ListItem` |
| **Trailing** (after text) | Indicate state or affordance (chevron, external-link, expand) | `Accordion`, `DisclosureMenu`, `MenuDropdown`, `ListItemNavigation`, `ListItemTrailingIcon`, `Subnavigation` |
| **Standalone** | Icon-only control with an accessible label | `IconButton` |
| **Decorative** | Visual flair on a surface | `Tile`, `DisclosureCard` (arrow), `StyledRadioGroup` |

## Sizing context

Use the size that matches the host component. The CSS handles sizing — do not set width/height in the SVG.

| Context | Size |
|---|---|
| Inline text, captions, list metadata | 16px |
| Buttons, form inputs, list items | 20–24px |
| Tiles, decorative card slots | 32–48px |
| Hero / full-page interruption | 48px+ |

## Passing icons

All icon props accept a `ReactNode` (an SVG element). Never pass an icon name as a string.

```tsx
import { Button, IconButton, NoticeBar } from 'arrow-react-bootstrap';
import { ChevronRightIcon, CloseIcon, InfoIcon } from './icons';

{/* Leading icon on a Button */}
<Button variant="primary" leadingIcon={<ChevronRightIcon />}>
  Continue
</Button>

{/* Standalone icon button — ariaLabel is required */}
<IconButton ariaLabel="Close menu" icon={<CloseIcon />} onClick={onClose} />

{/* Custom icon on an announcement NoticeBar */}
<NoticeBar
  variant="announcement"
  body="Service updates this weekend."
  leadingIcon={<InfoIcon />}
  leadingIconA11yLabel="Information"
/>
```

Common icon prop names across the library: `icon`, `leadingIcon`, `trailingIcon`, `closeIcon`, `decorationIcon`. Check the per-component file in `guidelines/components/{slug}.md` for the exact prop name on each component.

## Accessibility rules

- **`IconButton` requires `ariaLabel`.** It has no visible text — the label is the only thing a screen reader reads.
- **Decorative icons may be unlabeled.** When an icon sits next to text that already names the action ("Continue" with a chevron), the icon is decorative and does not need a label. Components handle this internally — do not add `aria-label` yourself.
- **Alert variants of `NoticeBar` auto-apply an icon and `role="alert"`.** Do not pass a `leadingIcon` for `caution`, `error`, or `positive` variants.
- **Never use an icon as the only meaningful element of a labeled control.** A `Button` whose only child is an icon and no `children`, `aria-label`, or `leadingIcon`+text is invisible to assistive tech. Use `IconButton` instead.

## Don'ts

- Don't import icons as strings or font glyphs — pass a real SVG `ReactNode`
- Don't nest icons inside extra `<span>` wrappers — Arrow's CSS targets the icon directly
- Don't recolor icons with inline styles — they inherit `currentColor` and respect `inverse`
- Don't mix a leading icon and a trailing icon on the same Button unless the design explicitly calls for both — pick one direction of emphasis

## Related

- `foundations/icons.md` — the Arrow icon set, naming conventions, and how to source SVGs
- `guidelines/components/icons.md` — the future `Icon` component (when published) for unified icon rendering
- `guidelines/components/icon-button.md` — full `IconButton` API
