# <motion-icon-state>

An icon that morphs between two states with spring physics: menu and close,
play and pause, copy and check, plus and minus, chevron down and up, an empty
and a filled heart, loading and done, and eye and eye-off. Drawn on a 24 px
grid with 2 px round strokes, so it sits next to Lucide, Tabler and Heroicons.

**Use it for:** controls and indicators that switch between two states,
such as a menu button, a play and pause control, a copy button that
confirms, or a like button.

**Avoid it for:** icons outside the eight built-in pairs, or icons that
only animate on hover or on scroll; use `motion-icon`, which takes any SVG.

**Accessibility:** with `toggle`, the icon gets `role="button"`,
`aria-pressed` that follows `active`, and `tabindex="0"` unless you set
one. Space and Enter switch it, and keyboard focus shows an outline.
`label` becomes the `aria-label`; without it, a toggle logs a warning and
falls back to the icon name, such as "menu". Without `toggle`, a `label`
gives the icon `role="img"`, and no `label` hides it from screen readers.

**Reduced motion:** the icon switches to the new state at once, with no
morph, and the loading spinner does not spin.

**Common mistakes:** setting `toggle` on an icon inside your own
`<button>`, which puts one button inside another; leave out `toggle` and
`label`, name the button, and set `active` from your code. Using a label
that fits only one state, such as "Open menu": the label does not change,
and `aria-pressed` already reports the state, so use a name such as "Menu".

Docs: https://www.motion-components.dev/docs/icons/motion-icon-state/

## Install

```js
import 'motion-components/motion-icon-state'
```

Or without a build step:

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/motion-components@1/dist/motion-icon-state.js/+esm"></script>
```

## Example

```html
<motion-icon-state name="menu" toggle label="Menu"></motion-icon-state>
<motion-icon-state name="heart" active></motion-icon-state>
```

## Attributes

| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `'menu' \| 'play' \| 'copy' \| 'plus' \| 'chevron' \| 'heart' \| 'loading' \| 'eye'` | `'menu'` | Which icon: `'menu'`, `'play'`, `'copy'`, `'plus'`, `'chevron'`, `'heart'`, `'loading'` or `'eye'`. |
| `active` | `boolean` | `false` | The second state: close, pause, check, minus, up, filled, done or eye-off. |
| `toggle` | `boolean` | `false` | Makes the icon a button that switches `active` on click, Space or Enter. |
| `label` | `string` | `''` | Accessible name. Without it (and without `toggle`) the icon is decorative. Required with `toggle`; a missing label logs a warning. |
| `duration` | `number` | `0.45` | Spring duration of the morph, in seconds. |
| `bounce` | `number` | `0.3` | Spring bounciness of the morph (0 = no overshoot). |

## Methods

| Method | Description |
| --- | --- |
| `flip()` | Switches `active` and fires `motion-change`, as a click on a `toggle` icon does. |

## Events

The `motion-*` events bubble and are composed.

| Event | Description |
| --- | --- |
| `motion-change` | When a click, key or `flip()` switches the state. Setting `active` does not fire it. `detail: { active }`. |

## CSS custom properties

| Property | Description |
| --- | --- |
| `--mc-icon-size` | Width and height of the icon. Default `1.5em`. |
| `--mc-icon-color` | Line color. Default `currentColor`. |
| `--mc-icon-color-active` | Color of the icon in its second state, when `active` is set, including the filled heart and the copy and loading checks. Default `--mc-icon-color`. |
