# IconToggle

> Two icons in one box that swap with a scale and fade, driven by a ToggleButton or your own state.

URL: https://apogee.avaui.dev/docs/icon-toggle
Last updated: 2026-10-15

Two icons in one box that swap with a scale and fade, driven by a ToggleButton or your own state.

Last updated October 15, 2026

Uses JavaScript

None of its own. ToggleButton’s island flips `data-on` on every IconToggle inside it when the button toggles; set `data-on` yourself anywhere else.

**Without JS:** The icon for the initial on value shows and stays; nothing swaps.

```astro
<ToggleButton iconOnly aria-label="Favourite">
<IconToggle>
  <Heart slot="off" />
  <Heart slot="on" class="fill-current" />
</IconToggle>
</ToggleButton>
```

## Add

```sh
npx @ava-ui/apogee add icon-toggle
```

No dependencies; pair it with `toggle-button`.

## Usage

```astro
---
import IconToggle from '@/components/apogee/IconToggle/IconToggle.astro'
import ToggleButton from '@/components/apogee/ToggleButton/ToggleButton.astro'
import { Star } from '@lucide/astro'
---
<ToggleButton iconOnly aria-label="Star">
  <IconToggle><Star slot="off" /><Star slot="on" class="fill-current" /></IconToggle>
</ToggleButton>
```

## API

`@composable` — exposed to Content Editors in AVA. Any other attribute passes through to the root `<span>`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `on` | `boolean` | `false` | Which icon shows. Rendered as `data-on`; flip that attribute to swap. |
| `label` | `string` | — | Accessible name (`role="img"`). Omit inside a labelled control, where the toggle is decorative. |
| `class` | `string` | — | Extra classes; set the size here (`size-5`). |

Slots: `off` and `on`, one icon each.

## Variants

Both `on` values, standalone:

```astro
<IconToggle label="Not starred"><Star slot="off" /><Star slot="on" class="fill-current" /></IconToggle>
<IconToggle on label="Starred"><Star slot="off" /><Star slot="on" class="fill-current" /></IconToggle>
```

## States

-   **Off / on** — the hidden icon is scaled to 60% and transparent; the swap takes `--duration-fast`.
-   **Reduced motion** — the swap is instant.

## Examples

A bookmark button. ToggleButton flips the icon and `aria-pressed` together:

```astro
<ToggleButton iconOnly aria-label="Bookmark" selectedColor="primary">
<IconToggle>
  <Bookmark slot="off" />
  <Bookmark slot="on" class="fill-current" />
</IconToggle>
</ToggleButton>
```

## Accessibility

-   Inside a ToggleButton the state is the button’s `aria-pressed`; the toggle is `aria-hidden`.
-   Standalone, give it a `label` that names the current state, and update it when you flip `data-on`.

## Tokens

| Token | Used for |
| --- | --- |
| `--duration-fast` / `--ease-standard` | Swap transition |

## Do / Don’t

-   **Do** pair outline and filled versions of the same glyph (heart, star, bookmark) so the swap reads as one control changing state.
-   **Don’t** use two unrelated icons for an on/off pair; use two buttons.

## Content

-   The button’s `aria-label` names the action, and stays the same in both states (“Bookmark”); `aria-pressed` carries the on/off state.

## Related

[

ToggleButtonA two-state button (aria-pressed) — icon and/or text, on or off.

](https://apogee.avaui.dev/docs/toggle-button)[

IconA library-agnostic icon wrapper — forwards a Lucide icon's props, or accepts a raw SVG slot, with built-in accessibility.

](https://apogee.avaui.dev/docs/icon)[

SwitchA toggle for an immediately-applied binary setting. A real checkbox under the hood, zero JS.

](https://apogee.avaui.dev/docs/switch)
