# IconPicker

**When to use:** Pick one item from a visual icon/image grid — category selectors, emoji-style pickers, avatar selectors, anything where each option is best represented by an icon or image rather than text alone.

**Keywords:** emoji picker, image grid picker

Follows the ARIA `radiogroup` pattern: one roving tab stop, arrow keys move focus **and** selection (wrapping from the last item to the first and back), Space/Enter selects the focused item.

**Import:** `import { IconPicker } from '@ahrowe/ui'`  
**Types:** `import type { IconPickerItem, IconPickerProps } from '@ahrowe/ui'`

```tsx
import { IconPicker, FormValidator } from '@ahrowe/ui';
import type { IconPickerItem } from '@ahrowe/ui';
import { faHouse, faCar, faTree } from '@fortawesome/free-solid-svg-icons';

const items: IconPickerItem[] = [
  { id: 'house', label: 'House',  icon: faHouse },
  { id: 'car',   label: 'Car',    icon: faCar },
  { id: 'tree',  label: 'Tree',   icon: faTree },
  { id: 'custom', label: 'Custom', customIcon: <img src="/logo.png" alt="" /> },
];

// Controlled
<IconPicker
  label="Category"
  data={items}
  selectedId={selectedId}
  onChange={(id) => setSelectedId(id)}
/>

// With FormValidator
const categoryValidator = new FormValidator<string | null>(null);
<IconPicker label="Category" data={items} formValidator={categoryValidator} isRequired />
```

**IconPickerItem:**

```ts
interface IconPickerItem {
  id: string;
  label: string;
  icon?: IconDefinition;       // FontAwesome icon
  customIcon?: React.ReactNode; // custom element (overrides icon)
}
```

**Key props:**

| Prop | Type | Description |
|------|------|-------------|
| `data` | `IconPickerItem[]` | Items to display in the grid |
| `selectedId` | `string \| null` | Currently selected item id |
| `label` | `string` | Floating label |
| `onChange` | `(id: string) => void` | Called when selection changes |
| `formValidator` | `FormValidator` | Connects to validation |
| `isRequired` | `boolean` | |

**Slots:** `root` `label` `itemContainer` `item`

## Selected state

A selected icon sits on `--primary-color` and draws itself in `--text-on-primary`. It used to inherit the page's `--text-color`, which meant the same selected state came out white on a dark theme and near-black on a light one.

## Sizing

Each icon's circular background is `1.5em`, so it stays proportional to the `1em` glyph inside it, as do the padding and the grid gaps.
