# Icon

`<wa-icon>`

Stable [Media](https://webawesome.com/docs/components/?category=media) [Since 2.0](https://webawesome.com/docs/resources/changelog#wa_200)

Icons are scalable vector symbols that represent actions, content, or status throughout your application. They support Font Awesome and custom icon libraries with animation presets.

Web Awesome comes bundled with over 2,000 free icons courtesy of [Font Awesome](https://fontawesome.com/). These icons are part of the `default` icon library. Font Awesome Pro users can unlock additional [icon families](#family-and-variant). Or, if you prefer, you can register your own [custom icon library](#third-party-icon-libraries).

```html
<div class="icon-rebuses" style="font-size: 2em;">
  <!-- Catfish -->
  <wa-icon name="cat"></wa-icon>
  <wa-icon name="fish"></wa-icon>

  <!-- Brainstorm -->
  <wa-icon name="brain"></wa-icon>
  <wa-icon name="cloud-bolt"></wa-icon>

  <!-- Bookworm -->
  <wa-icon name="book"></wa-icon>
  <wa-icon name="worm"></wa-icon>

  <!-- Moonwalk -->
  <wa-icon name="moon"></wa-icon>
  <wa-icon name="person-walking"></wa-icon>
</div>

<style>
  /* Space between each rebus pair: trailing margin on every 2nd icon */
  .icon-rebuses wa-icon:nth-of-type(2n):not(:last-of-type) {
    margin-inline-end: var(--wa-space-m);
  }
</style>
```

Not sure which icon to use? [Find the perfect icon over at Font Awesome!](https://fontawesome.com/search?o=r&m=free&f=brands%2Cclassic)

## Custom Icons

Custom icons can be loaded individually with the `src` attribute. Only SVGs on a local or CORS-enabled endpoint are supported. If you're using more than one custom icon, it might make sense to register a [custom icon library](#third-party-icon-libraries).

```html
<wa-icon src="https://shoelace.style/assets/images/shoe.svg" style="font-size: 4rem;"></wa-icon>
```

## Icon Libraries

An icon library is a named set of icons with a resolver that maps each name to an SVG URL. Web Awesome ships with two built-in libraries and lets you register any number of your own.

| Library | Contains | Resolves from | Customize it to… |
| --- | --- | --- | --- |
| \`default\` | \`

[sizing](#size), [color](#color), [the canvas](#canvas), [rotating and flipping](#rotating-and-flipping), and [animations](#animating) work with icons from any library — they're applied to the `<wa-icon>` host, so they don't depend on where the icon comes from. (Only the duotone color properties are specific to Font Awesome's duotone icons.)

### Customizing the Default Library

To resolve the default icons elsewhere (a different set, or your own server), register a library using the `default` name and a custom resolver.

For example, this will change the default icon library to use [Bootstrap Icons](https://icons.getbootstrap.com/) loaded from the jsDelivr CDN.

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('default', {
    resolver: (name, family) => {
      const suffix = family === 'filled' ? '-fill' : '';
      return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/icons/${name}${suffix}.svg`;
    },
  });
</script>
```

#### Self-Hosting

By default, icons are loaded from the Font Awesome CDN. If you'd prefer to [download the icons](https://fontawesome.com/download) and serve them from your own server, you can use the `setIconPath()` function to point the default icon library at your self-hosted directory.

When you download Font Awesome, the archive will contain an `svgs` directory with subfolders such as `solid/`, `regular/`, `brands/`, etc. Copy the `svgs` directory (or its contents) into your project and set the icon path to point to it.

```html
<script type="module">
  import { setIconPath } from '/dist/webawesome.js';

  // Point to the `svgs` directory from your Font Awesome download
  setIconPath('/assets/fontawesome/svgs');
</script>
```

After calling `setIconPath()`, icons will resolve to your self-hosted directory instead of the CDN. For example, `<wa-icon name="house">` will load from `/assets/fontawesome/svgs/solid/house.svg`.

For more control over how icon URLs are constructed, you can use the `getIconFolder()` helper along with `registerIconLibrary()` to build a custom resolver. The `getIconFolder()` function maps a family and variant to the correct folder name, so you don't have to replicate that logic yourself.

```html
<script type="module">
  import { getIconFolder, registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('default', {
    resolver: (name, family, variant) => {
      const folder = getIconFolder(name, family, variant);
      return `/assets/fontawesome/svgs/${folder}/${name}.svg?v=2`;
    },
  });
</script>
```

**Call `setIconPath()` before Web Awesome components load.**  
Like `setBasePath()` and `setKitCode()`, it has no effect once components have initialized.

#### SVG Sprites

To improve performance you can use a SVG sprites to avoid multiple trips for each SVG. The browser will load the sprite sheet once and then you reference the particular SVG within the sprite sheet using hash selector.

As always, make sure to benchmark these changes. When using HTTP/2, it may in fact be more bandwidth-friendly to use multiple small requests instead of 1 large sprite sheet.

**Only use sprite sheets you self-host.**  
Browsers apply the same-origin policy to the `<use>` elements inside `<wa-icon>`'s shadow DOM and may refuse a cross-origin URL, with no way to override it. `wa-load` and `wa-error` also don't fire for sprite-sheet icons.

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('sprite', {
    resolver: name => `/assets/images/sprite.svg#${name}`,
    mutator: svg => svg.setAttribute('fill', 'currentColor'),
    spriteSheet: true,
  });
</script>
```

### Customizing the System Library

To change the icons Web Awesome uses internally, register a library using the `system` name and a custom resolver. You're then responsible for providing every icon components require. See `src/components/library.system.ts` for the full list.

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('system', {
    resolver: name => `/path/to/custom/icons/${name}.svg`,
  });
</script>
```

### Third-Party Icon Libraries

Register any number of additional libraries with the `registerIconLibrary()` function exported from `dist/webawesome.js`. Provide a name and a **resolver** that maps an icon name to its SVG URL (local or a CORS-enabled CDN). Icons are fetched only when used, so a registered library you don't touch costs nothing.

Some libraries need a **mutator** to adjust each SVG on load, most often setting `fill` or `stroke` to `currentColor` so icons inherit the text color.

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('my-icons', {
    resolver: (name, family, variant) => `/assets/icons/${name}.svg`,
    mutator: svg => svg.setAttribute('fill', 'currentColor'),
  });
</script>
```

Then reference an icon by its `library` and `name`. (An icon used before its library registers stays blank until it does.)

```html
<!-- This will show the icon located at /assets/icons/smile.svg -->
<wa-icon library="my-icons" name="smile"></wa-icon>
```

The examples below register popular open-source libraries via CDN. Adapt them to your own origin or naming.

#### Bootstrap Icons

This will register the [Bootstrap Icons](https://icons.getbootstrap.com/) library using the jsDelivr CDN. This library has two families: `regular` and `filled`.

Icons in this library are licensed under the [MIT License](https://github.com/twbs/icons/blob/main/LICENSE).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('bootstrap', {
    resolver: (name, family) => {
      const suffix = family === 'filled' ? '-fill' : '';
      return `https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/icons/${name}${suffix}.svg`;
    },
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="bootstrap" name="backpack"></wa-icon>
  <wa-icon library="bootstrap" name="cup-hot"></wa-icon>
  <wa-icon library="bootstrap" name="envelope-heart"></wa-icon>
  <wa-icon library="bootstrap" name="inboxes"></wa-icon>
  <wa-icon library="bootstrap" name="lamp"></wa-icon>
  <wa-icon library="bootstrap" name="piggy-bank"></wa-icon>
  <br />
  <wa-icon library="bootstrap" family="filled" name="backpack"></wa-icon>
  <wa-icon library="bootstrap" family="filled" name="cup-hot"></wa-icon>
  <wa-icon library="bootstrap" family="filled" name="envelope-heart"></wa-icon>
  <wa-icon library="bootstrap" family="filled" name="inboxes"></wa-icon>
  <wa-icon library="bootstrap" family="filled" name="lamp"></wa-icon>
  <wa-icon library="bootstrap" family="filled" name="piggy-bank"></wa-icon>
</div>
```

#### Boxicons

This will register the [Boxicons](https://boxicons.com/) library using the jsDelivr CDN. This library has three variations: regular (`bx-*`), solid (`bxs-*`), and logos (`bxl-*`). A mutator function is required to set the SVG's `fill` to `currentColor`.

Icons in this library are licensed under the [Creative Commons 4.0 License](https://github.com/atisawd/boxicons#license).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('boxicons', {
    resolver: name => {
      let folder = 'regular';
      if (name.substring(0, 4) === 'bxs-') folder = 'solid';
      if (name.substring(0, 4) === 'bxl-') folder = 'logos';
      return `https://cdn.jsdelivr.net/npm/boxicons@2.1.4/svg/${folder}/${name}.svg`;
    },
    mutator: svg => svg.setAttribute('fill', 'currentColor'),
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="boxicons" name="bx-bot"></wa-icon>
  <wa-icon library="boxicons" name="bx-cookie"></wa-icon>
  <wa-icon library="boxicons" name="bx-joystick"></wa-icon>
  <wa-icon library="boxicons" name="bx-save"></wa-icon>
  <wa-icon library="boxicons" name="bx-server"></wa-icon>
  <wa-icon library="boxicons" name="bx-wine"></wa-icon>
  <br />
  <wa-icon library="boxicons" name="bxs-bot"></wa-icon>
  <wa-icon library="boxicons" name="bxs-cookie"></wa-icon>
  <wa-icon library="boxicons" name="bxs-joystick"></wa-icon>
  <wa-icon library="boxicons" name="bxs-save"></wa-icon>
  <wa-icon library="boxicons" name="bxs-server"></wa-icon>
  <wa-icon library="boxicons" name="bxs-wine"></wa-icon>
  <br />
  <wa-icon library="boxicons" name="bxl-apple"></wa-icon>
  <wa-icon library="boxicons" name="bxl-chrome"></wa-icon>
  <wa-icon library="boxicons" name="bxl-edge"></wa-icon>
  <wa-icon library="boxicons" name="bxl-firefox"></wa-icon>
  <wa-icon library="boxicons" name="bxl-opera"></wa-icon>
  <wa-icon library="boxicons" name="bxl-microsoft"></wa-icon>
</div>
```

#### Lucide

This will register the [Lucide](https://lucide.dev/) icon library using the jsDelivr CDN. This project is a community-maintained fork of the popular [Feather](https://feathericons.com/) icon library.

Icons in this library are licensed under the [MIT License](https://github.com/lucide-icons/lucide/blob/master/LICENSE).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('lucide', {
    resolver: name => `https://cdn.jsdelivr.net/npm/lucide-static@1.8.0/icons/${name}.svg`,
    mutator: svg =>
      svg.querySelectorAll('path').forEach(path => {
        path.setAttribute('fill', 'none');
        path.setAttribute('stroke', 'currentColor');
      }),
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="lucide" name="feather"></wa-icon>
  <wa-icon library="lucide" name="pie-chart"></wa-icon>
  <wa-icon library="lucide" name="settings"></wa-icon>
  <wa-icon library="lucide" name="map-pin"></wa-icon>
  <wa-icon library="lucide" name="printer"></wa-icon>
  <wa-icon library="lucide" name="shopping-cart"></wa-icon>
</div>
```

#### Heroicons

This will register the [Heroicons](https://heroicons.com/) library using the jsDelivr CDN.

Icons in this library are licensed under the [MIT License](https://github.com/tailwindlabs/heroicons/blob/master/LICENSE).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('heroicons', {
    resolver: name => `https://cdn.jsdelivr.net/npm/heroicons@2.2.0/24/outline/${name}.svg`,
    mutator: svg =>
      svg.querySelectorAll('path').forEach(path => {
        path.setAttribute('fill', 'none');
        path.setAttribute('stroke', 'currentColor');
      }),
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="heroicons" name="chat-bubble-left"></wa-icon>
  <wa-icon library="heroicons" name="cloud"></wa-icon>
  <wa-icon library="heroicons" name="cog"></wa-icon>
  <wa-icon library="heroicons" name="document-text"></wa-icon>
  <wa-icon library="heroicons" name="gift"></wa-icon>
  <wa-icon library="heroicons" name="speaker-wave"></wa-icon>
</div>
```

#### Iconoir

This will register the [Iconoir](https://iconoir.com/) library using the jsDelivr CDN.

Icons in this library are licensed under the [MIT License](https://github.com/lucaburgio/iconoir/blob/master/LICENSE).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('iconoir', {
    resolver: (name, family) => {
      return `https://cdn.jsdelivr.net/npm/iconoir@7.11.0/icons/regular/${name}.svg`;
    },
    mutator: svg =>
      svg.querySelectorAll('path').forEach(path => {
        path.setAttribute('fill', 'none');
        path.setAttribute('stroke', 'currentColor');
      }),
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="iconoir" name="check-circle"></wa-icon>
  <wa-icon library="iconoir" name="drawer"></wa-icon>
  <wa-icon library="iconoir" name="keyframes"></wa-icon>
  <wa-icon library="iconoir" name="headset-help"></wa-icon>
  <wa-icon library="iconoir" name="color-picker"></wa-icon>
  <wa-icon library="iconoir" name="wifi"></wa-icon>
</div>
```

#### Ionicons

This will register the [Ionicons](https://ionicons.com/) library using the jsDelivr CDN. This library has three variations: outline (default), filled (`*-filled`), and sharp (`*-sharp`). A mutator function is required to polyfill a handful of styles we're not including.

Icons in this library are licensed under the [MIT License](https://github.com/ionic-team/ionicons/blob/master/LICENSE).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('ionicons', {
    resolver: name => `https://cdn.jsdelivr.net/npm/ionicons@8.0.13/dist/ionicons/svg/${name}.svg`,
    mutator: svg => {
      svg.setAttribute('fill', 'currentColor');
      svg.setAttribute('stroke', 'currentColor');
      [...svg.querySelectorAll('.ionicon-fill-none')].map(el => el.setAttribute('fill', 'none'));
      [...svg.querySelectorAll('.ionicon-stroke-width')].map(el => el.setAttribute('stroke-width', '32px'));
    },
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="ionicons" name="alarm"></wa-icon>
  <wa-icon library="ionicons" name="american-football"></wa-icon>
  <wa-icon library="ionicons" name="bug"></wa-icon>
  <wa-icon library="ionicons" name="chatbubble"></wa-icon>
  <wa-icon library="ionicons" name="settings"></wa-icon>
  <wa-icon library="ionicons" name="warning"></wa-icon>
  <br />
  <wa-icon library="ionicons" name="alarm-outline"></wa-icon>
  <wa-icon library="ionicons" name="american-football-outline"></wa-icon>
  <wa-icon library="ionicons" name="bug-outline"></wa-icon>
  <wa-icon library="ionicons" name="chatbubble-outline"></wa-icon>
  <wa-icon library="ionicons" name="settings-outline"></wa-icon>
  <wa-icon library="ionicons" name="warning-outline"></wa-icon>
  <br />
  <wa-icon library="ionicons" name="alarm-sharp"></wa-icon>
  <wa-icon library="ionicons" name="american-football-sharp"></wa-icon>
  <wa-icon library="ionicons" name="bug-sharp"></wa-icon>
  <wa-icon library="ionicons" name="chatbubble-sharp"></wa-icon>
  <wa-icon library="ionicons" name="settings-sharp"></wa-icon>
  <wa-icon library="ionicons" name="warning-sharp"></wa-icon>
</div>
```

#### Jam Icons

This will register the [Jam Icons](https://jam-icons.com/) library using the jsDelivr CDN. This library has two variations: regular (default) and filled (`*-f`). A mutator function is required to set the SVG's `fill` to `currentColor`.

Icons in this library are licensed under the [MIT License](https://github.com/michaelampr/jam/blob/master/LICENSE).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('jam', {
    resolver: name => `https://cdn.jsdelivr.net/npm/jam-icons@2.0.0/svg/${name}.svg`,
    mutator: svg => svg.setAttribute('fill', 'currentColor'),
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="jam" name="calendar"></wa-icon>
  <wa-icon library="jam" name="camera"></wa-icon>
  <wa-icon library="jam" name="filter"></wa-icon>
  <wa-icon library="jam" name="leaf"></wa-icon>
  <wa-icon library="jam" name="picture"></wa-icon>
  <wa-icon library="jam" name="set-square"></wa-icon>
  <br />
  <wa-icon library="jam" name="calendar-f"></wa-icon>
  <wa-icon library="jam" name="camera-f"></wa-icon>
  <wa-icon library="jam" name="filter-f"></wa-icon>
  <wa-icon library="jam" name="leaf-f"></wa-icon>
  <wa-icon library="jam" name="picture-f"></wa-icon>
  <wa-icon library="jam" name="set-square-f"></wa-icon>
</div>
```

#### Material Icons

This will register the [Material Icons](https://material.io/resources/icons/?style=baseline) library using the jsDelivr CDN. This library has three variations: outline (default), round (`*_round`), and sharp (`*_sharp`). A mutator function is required to set the SVG's `fill` to `currentColor`.

Icons in this library are licensed under the [Apache 2.0 License](https://github.com/google/material-design-icons/blob/master/LICENSE).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('material', {
    resolver: name => {
      const match = name.match(/^(.*?)(_(round|sharp))?$/);
      return `https://cdn.jsdelivr.net/npm/@material-icons/svg@1.0.33/svg/${match[1]}/${match[3] || 'outline'}.svg`;
    },
    mutator: svg => svg.setAttribute('fill', 'currentColor'),
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="material" name="notifications"></wa-icon>
  <wa-icon library="material" name="email"></wa-icon>
  <wa-icon library="material" name="delete"></wa-icon>
  <wa-icon library="material" name="volume_up"></wa-icon>
  <wa-icon library="material" name="settings"></wa-icon>
  <wa-icon library="material" name="shopping_basket"></wa-icon>
  <br />
  <wa-icon library="material" name="notifications_round"></wa-icon>
  <wa-icon library="material" name="email_round"></wa-icon>
  <wa-icon library="material" name="delete_round"></wa-icon>
  <wa-icon library="material" name="volume_up_round"></wa-icon>
  <wa-icon library="material" name="settings_round"></wa-icon>
  <wa-icon library="material" name="shopping_basket_round"></wa-icon>
  <br />
  <wa-icon library="material" name="notifications_sharp"></wa-icon>
  <wa-icon library="material" name="email_sharp"></wa-icon>
  <wa-icon library="material" name="delete_sharp"></wa-icon>
  <wa-icon library="material" name="volume_up_sharp"></wa-icon>
  <wa-icon library="material" name="settings_sharp"></wa-icon>
  <wa-icon library="material" name="shopping_basket_sharp"></wa-icon>
</div>
```

#### Remix Icon

This will register the [Remix Icon](https://remixicon.com/) library using the jsDelivr CDN. This library groups icons by categories, so the name must include the category and icon separated by a slash, as well as the `-line` or `-fill` suffix as needed. A mutator function is required to set the SVG's `fill` to `currentColor`.

Icons in this library are licensed under the [Apache 2.0 License](https://github.com/Remix-Design/RemixIcon/blob/master/License).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('remixicon', {
    resolver: name => {
      const match = name.match(/^(.*?)\/(.*?)?$/);
      match[1] = match[1].charAt(0).toUpperCase() + match[1].slice(1);
      return `https://cdn.jsdelivr.net/npm/remixicon@4.9.1/icons/${match[1]}/${match[2]}.svg`;
    },
    mutator: svg => svg.setAttribute('fill', 'currentColor'),
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="remixicon" name="business/cloud-line"></wa-icon>
  <wa-icon library="remixicon" name="design/brush-line"></wa-icon>
  <wa-icon library="remixicon" name="business/pie-chart-line"></wa-icon>
  <wa-icon library="remixicon" name="development/bug-line"></wa-icon>
  <wa-icon library="remixicon" name="media/image-line"></wa-icon>
  <wa-icon library="remixicon" name="system/alert-line"></wa-icon>
  <br />
  <wa-icon library="remixicon" name="business/cloud-fill"></wa-icon>
  <wa-icon library="remixicon" name="design/brush-fill"></wa-icon>
  <wa-icon library="remixicon" name="business/pie-chart-fill"></wa-icon>
  <wa-icon library="remixicon" name="development/bug-fill"></wa-icon>
  <wa-icon library="remixicon" name="media/image-fill"></wa-icon>
  <wa-icon library="remixicon" name="system/alert-fill"></wa-icon>
</div>
```

#### Tabler Icons

This will register the [Tabler Icons](https://tabler-icons.io/) library using the jsDelivr CDN. This library features over 1,950 open source icons.

Icons in this library are licensed under the [MIT License](https://github.com/tabler/tabler-icons/blob/master/LICENSE).

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('tabler', {
    resolver: name => `https://cdn.jsdelivr.net/npm/@tabler/icons@2.47.0/icons/${name}.svg`,
    mutator: svg => {
      svg.style.fill = 'none';
      svg.setAttribute('stroke', 'currentColor');
    },
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="tabler" name="alert-triangle"></wa-icon>
  <wa-icon library="tabler" name="arrow-back"></wa-icon>
  <wa-icon library="tabler" name="at"></wa-icon>
  <wa-icon library="tabler" name="ball-baseball"></wa-icon>
  <wa-icon library="tabler" name="cake"></wa-icon>
  <wa-icon library="tabler" name="files"></wa-icon>
  <br />
  <wa-icon library="tabler" name="keyboard"></wa-icon>
  <wa-icon library="tabler" name="moon"></wa-icon>
  <wa-icon library="tabler" name="pig"></wa-icon>
  <wa-icon library="tabler" name="printer"></wa-icon>
  <wa-icon library="tabler" name="ship"></wa-icon>
  <wa-icon library="tabler" name="toilet-paper"></wa-icon>
</div>
```

#### Unicons

This will register the [Unicons](https://iconscout.com/unicons) library using the jsDelivr CDN. This library has two variations: line (default) and solid (`*-s`). A mutator function is required to set the SVG's `fill` to `currentColor`.

Icons in this library are licensed under the [Apache 2.0 License](https://github.com/Iconscout/unicons/blob/master/LICENSE). Some of the icons that appear on the Unicons website, particularly many of the solid variations, require a license and are therefore not available in the CDN.

```html
<script type="module">
  import { registerIconLibrary } from '/dist/webawesome.js';

  registerIconLibrary('unicons', {
    resolver: name => {
      const match = name.match(/^(.*?)(-s)?$/);
      return `https://cdn.jsdelivr.net/npm/@iconscout/unicons@4.2.0/svg/${match[2] === '-s' ? 'solid' : 'line'}/${
        match[1]
      }.svg`;
    },
    mutator: svg => svg.setAttribute('fill', 'currentColor'),
  });
</script>

<div style="font-size: 24px;">
  <wa-icon library="unicons" name="clock"></wa-icon>
  <wa-icon library="unicons" name="graph-bar"></wa-icon>
  <wa-icon library="unicons" name="padlock"></wa-icon>
  <wa-icon library="unicons" name="polygon"></wa-icon>
  <wa-icon library="unicons" name="rocket"></wa-icon>
  <wa-icon library="unicons" name="star"></wa-icon>
  <br />
  <wa-icon library="unicons" name="clock-s"></wa-icon>
  <wa-icon library="unicons" name="graph-bar-s"></wa-icon>
  <wa-icon library="unicons" name="padlock-s"></wa-icon>
  <wa-icon library="unicons" name="polygon-s"></wa-icon>
  <wa-icon library="unicons" name="rocket-s"></wa-icon>
  <wa-icon library="unicons" name="star-s"></wa-icon>
</div>
```

## Accessibility Considerations

Web Awesome hides an unlabeled `<wa-icon>` from assistive devices, so an icon is presentational unless you give it a name. The two things to get right are labeling icons that carry meaning and respecting users who prefer less motion.

### Labeling Icons

Give an icon a `label` when it carries meaning on its own — when it's the only content of a control, or conveys status. Omit it when nearby text already says the same; unlabeled icons are hidden from assistive devices.

| Scenario | Label? | In Context | Why |
| --- | --- | --- | --- |
| Icon-only control | Yes | | \`label\` The icon is the button's only content, so the gives it an accessible name. |
| Status icon | Yes | Invoice #1042 | The icon conveys status the nearby text doesn't. |
| Icon beside its own text | No | Share | The visible “Share” text already names the action; a label would be announced twice. |
| Decorative | No | Check your inbox | It only decorates text that already carries the meaning. |

Set the `label` attribute to the text a screen reader should announce:

```html
<wa-icon name="circle-check" label="Task complete" style="font-size: 2em;"></wa-icon>
<wa-icon name="triangle-exclamation" label="Warning" style="font-size: 2em;"></wa-icon>
<wa-icon name="trash" label="Delete" style="font-size: 2em;"></wa-icon>
<wa-icon name="bell" label="Notifications" style="font-size: 2em;"></wa-icon>
```

### Reduced Motion

All [icon animations](#animating) honor the user's `prefers-reduced-motion` setting — when it's set to `reduce`, Web Awesome disables them automatically so motion never becomes a barrier. See [Font Awesome's animation accessibility notes](https://docs.fontawesome.com/web/style/animate/#accessibility) for more.

## API

### Importing

If you're using the autoloader or a hosted project, components load on demand — no manual import needed. To cherry-pick a component manually, use one of the following snippets.

\*\*CDN\*\*

Import this component directly from the CDN:

```js
import 'https://ka-f.webawesome.com/webawesome@3.11.0/components/icon/icon.js';
```

\*\*npm\*\*

After installing Web Awesome via npm, import this component:

```js
import '@awesome.me/webawesome/dist/components/icon/icon.js';
```

\*\*Self-Hosted\*\*

If you're self-hosting Web Awesome, import this component from your server:

```js
import './webawesome/dist/components/icon/icon.js';
```

\*\*React\*\*

To import this component for React 18 or below, use the following code:

```js
import WaIcon from '@awesome.me/webawesome/dist/react/icon/index.js';
```

### Attributes & Properties

| Name | Description | Reflects |
| --- | --- | --- |
| \`animation\` animation | \`IconAnimation \\| undefined\` Sets the animation for the icon Type | |
| \`autoWidth\` auto-width | \`fa-width-auto\` Sets the width of the icon to match the cropped SVG viewBox. This operates like the Font class. Type boolean Default false | |
| \`canvas\` canvas | \`fixed\` Sets the icon canvas — the box the icon is centered within. Unset renders as (1.25em × 1em); auto hugs the icon's width; square is 1.25em × 1.25em; roomy is 1.5em × 1.5em. Mirrors Font Awesome's fa-fixed-width, fa-width-auto, fa-canvas-square, and fa-canvas-roomy. Scales with font-size. Type IconCanvas \\| undefined | |
| \`family\` family | \`classic\` The family of icons to choose from. For Font Awesome Free, valid options include and brands. For Font Awesome Pro subscribers, valid options include, classic, sharp, duotone, sharp-duotone, and brands. A valid kit code must be present to show pro icons via CDN. You can set to provide one. Type string | |
| \`flip\` flip | \`'x' \\| 'y' \\| 'both' \\| undefined\` Sets the flip direction of the icon along the 'x' (horizontal), 'y' (vertical), or 'both' axes. Type | |
| \`label\` label | \`string\` An alternate description to use for assistive devices. If omitted, the icon will be considered presentational and ignored by assistive devices. Type Default '' | |
| \`library\` library | \`string\` The name of a registered custom icon library. Type Default 'default' | |
| \`name\` name | \`string \\| undefined\` The name of the icon to draw. Available names depend on the icon library being used. Type | |
| \`rotate\` rotate | \`number\` Sets the rotation degree of the icon Type Default 0 | |
| \`src\` src | \`string \\| undefined\` An external URL of an SVG file. Be sure you trust the content you are including, as it will be executed as code and can result in XSS attacks. Type | |
| \`swapOpacity\` swap-opacity | \`boolean\` Swaps the opacity of duotone icons. Type Default false | |
| \`variant\` variant | \`thin\` The name of the icon's variant. For Font Awesome, valid options include , light, regular, and solid for the classic and sharp families. Some variants require a Font Awesome Pro subscription. Custom icon libraries may or may not use this property. Type string | |

### Events

| Name | Description |
| --- | --- |
| \`wa-error\` | \`spriteSheet: true\` Emitted when the icon fails to load due to an error. When using this will not emit. |
| \`wa-load\` | \`spriteSheet: true\` Emitted when the icon has loaded. When using this will not emit. |

### CSS Custom Properties

| Name | Description |
| --- | --- |
| \`--animation-delay\` | \`0\` Sets when the animation will start. Default |
| \`--animation-direction\` | \`normal\` Defines whether or not the animation should play in reverse on alternate cycles. Default |
| \`--animation-duration\` | \`1s\` Defines the length of time that an animation takes to complete one cycle. Default |
| \`--animation-iteration-count\` | \`infinite\` Defines the number of times an animation cycle is played. Default |
| \`--animation-timing\` | Describes how the animation will progress over one cycle of its duration. |
| \`--beat-fade-opacity\` | \`beat-fade\` Set lowest opacity value an icon with animation will fade to and from. |
| \`--beat-fade-scale\` | \`beat-fade\` Set max value that an icon with animation will scale. |
| \`--beat-scale\` | \`beat\` Set the scale multiplier for an icon with animation. This multiplies the animation's 1.25× base pulse, so the default 1.25 peaks at ~1.56× and 2 roughly doubles the pulse. |
| \`--bounce-anticipation\` | \`bounce\` Set the downward squash distance before an icon with animation jumps. |
| \`--bounce-height\` | \`bounce\` Set the max height an icon with animation will jump to when bouncing. |
| \`--bounce-jump-scale-x\` | Set the icon’s horizontal distortion (“squish”) at the top of the jump. |
| \`--bounce-jump-scale-y\` | Set the icon’s vertical distortion (“squish”) at the top of the jump. |
| \`--bounce-land-scale-x\` | Set the icon’s horizontal distortion (“squish”) when landing after the jump. |
| \`--bounce-land-scale-y\` | Set the icon’s vertical distortion (“squish”) when landing after the jump. |
| \`--bounce-rebound\` | \`bounce\` Set the amount of rebound an icon with animation has when landing after the jump. |
| \`--bounce-start-scale-x\` | Set the icon’s horizontal distortion (“squish”) when starting to bounce. |
| \`--bounce-start-scale-y\` | Set the icon’s vertical distortion (“squish”) when starting to bounce. |
| \`--buzz-distance\` | \`buzz\` Set the horizontal travel of an icon with animation. |
| \`--fade-opacity\` | \`fade\` Set lowest opacity value an icon with animation will fade to and from. |
| \`--flip-angle\` | \`flip\` Set rotation angle of for an icon with flip or flip-360 animation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise one. |
| \`--flip-anticipation-scale\` | \`flip\` Set the scale of the wind-up before an icon with or flip-360 animation rotates. |
| \`--flip-overshoot\` | \`flip\` Set how far past the final angle an icon with or flip-360 animation rotates before settling. |
| \`--flip-x\` | \`flip\` Set x-coordinate of the vector denoting the axis of rotation (between 0 and 1) for an icon with or flip-360 animation. |
| \`--flip-y\` | \`flip\` Set y-coordinate of the vector denoting the axis of rotation (between 0 and 1) for an icon with or flip-360 animation. |
| \`--flip-z\` | \`flip\` Set z-coordinate of the vector denoting the axis of rotation (between 0 and 1) for an icon with or flip-360 animation. |
| \`--float-drift\` | \`float\` Set the horizontal drift of an icon with animation. |
| \`--float-height\` | \`float\` Set the rise height of an icon with animation. |
| \`--float-squash-x\` | \`float\` Set the horizontal squash of an icon with animation at rest. |
| \`--float-squash-y\` | \`float\` Set the vertical squash of an icon with animation at rest. |
| \`--float-stretch-x\` | \`float\` Set the horizontal stretch of an icon with animation at its peak. |
| \`--float-stretch-y\` | \`float\` Set the vertical stretch of an icon with animation at its peak. |
| \`--float-tilt\` | \`float\` Set the rotation of an icon with animation. |
| \`--jello-scale-x\` | \`jello\` Set the horizontal stretch of an icon with animation. |
| \`--jello-scale-y\` | \`jello\` Set the vertical stretch of an icon with animation. |
| \`--primary-color\` | \`currentColor\` Sets a duotone icon's primary color. Default |
| \`--primary-opacity\` | \`1\` Sets a duotone icon's primary opacity. Default |
| \`--secondary-color\` | \`currentColor\` Sets a duotone icon's secondary color. Default |
| \`--secondary-opacity\` | \`0.4\` Sets a duotone icon's secondary opacity. Default |
| \`--swing-angle\` | \`swing\` Set the peak rotation of an icon with animation. |
| \`--wag-angle\` | \`wag\` Set the peak rotation of an icon with animation. |

### CSS Parts

| Name | Description | CSS selector |
| --- | --- | --- |
| \`svg\` | The internal SVG element. | \`::part(svg)\` |
| \`use\` | \`\` The element generated when using spriteSheet: true | \`::part(use)\` |

## Examples

### Size

Icons are sized relative to the current font size. To change their size, set the `font-size` property on the icon itself or on a parent element — drag the slider to see it in action.

```html
<div class="icon-sizing">
  <div class="wa-cluster icon-sizing-preview" style="font-size: 2rem;">
    <wa-icon name="bell"></wa-icon>
    <wa-icon name="heart"></wa-icon>
    <wa-icon name="image"></wa-icon>
    <wa-icon name="microphone"></wa-icon>
    <wa-icon name="search"></wa-icon>
    <wa-icon name="star"></wa-icon>
  </div>

  <wa-divider></wa-divider>

  <wa-slider label="Font size" min="0" max="4" value="2" with-markers>
    <span slot="reference">1rem</span>
    <span slot="reference">1.5rem</span>
    <span slot="reference">2rem</span>
    <span slot="reference">3rem</span>
    <span slot="reference">4rem</span>
  </wa-slider>
</div>

<style>
  .icon-sizing-preview {
    min-height: 6rem;
    align-items: center;
    justify-content: center;
    margin-block-end: 1.5rem;
  }
</style>

<script>
  (() => {
    const container = document.querySelector('.icon-sizing');
    const preview = container.querySelector('.icon-sizing-preview');
    const slider = container.querySelector('wa-slider');
    const sizes = ['1rem', '1.5rem', '2rem', '3rem', '4rem'];
    slider.addEventListener('input', () => (preview.style.fontSize = sizes[slider.value]));
  })();
</script>
```

### Color

Icons inherit their color from the current text color. Thus, you can set the `color` property on the `<wa-icon>` element or an ancestor to change the color.

```html
<div class="wa-cluster" style="font-size: 1.5em;">
  <wa-icon name="heart" style="color: salmon;"></wa-icon>
  <wa-icon name="fire" style="color: coral;"></wa-icon>
  <wa-icon name="sun" style="color: gold;"></wa-icon>
  <wa-icon name="leaf" style="color: mediumseagreen;"></wa-icon>
  <wa-icon name="cloud-showers-heavy" style="color: steelblue;"></wa-icon>
  <wa-icon name="hat-wizard" style="color: mediumpurple;"></wa-icon>
</div>
```

### Family & Variant

A _family_ sets an icon's overall style; a _variant_ sets its weight. Set them with the `family` and `variant` attributes — `family` defaults to `classic` and `variant` to `solid`.

| Family | Variants | Plan |
| --- | --- | --- |
| \`classic\` default | \`solid\` default, regular, light, thin | Free |
| \`brands\` | — | Free |
| \`duotone\` | \`solid\` , regular, light, thin | Pro |
| \`sharp\` | \`solid\` , regular, light, thin | Pro |
| \`sharp-duotone\` | \`solid\` , regular, light, thin | Pro | The `light` and `thin` variants, the `sharp`, `duotone`, and `sharp-duotone` families, and the [Pro+ packs](#font-awesome-pro-icons) require a Font Awesome Pro plan. [Provide a Kit code](https://webawesome.com/docs/#using-font-awesome-kit-codes) to unlock them.

### Canvas

The _canvas_ is the box an icon sits in. Choose one of four mutually exclusive modes with the `canvas` attribute (the default is `fixed`). It mirrors [Font Awesome's icon canvas](https://docs.fontawesome.com/web/style/icon-canvas/) and scales with `font-size`, independent of [sizing](#size). The tinted box below shows each canvas's extent.

| Canvas | Box | Best For | Example |
| --- | --- | --- | --- |
| \`fixed\` default | \`1.25 × 1em\` | Aligning icons in lists, menus, and toolbars | |
| \`auto\` | \`auto × 1em\` | Matching the icon's natural width | |
| \`square\` | \`1.25 × 1.25em\` | Standalone icons on a square footprint | |
| \`roomy\` | \`1.5 × 1.5em\` | Standalone icons that need more breathing room | |

```html
<div class="canvas-demo">
  <div class="canvas-demo-preview wa-cluster">
    <wa-icon
      name="ruler-horizontal"
      style="background: var(--wa-color-brand-fill-quiet); border: var(--wa-border-width-s) dashed var(--wa-color-brand-border-loud);"
    ></wa-icon>
    <wa-icon
      name="image"
      style="background: var(--wa-color-brand-fill-quiet); border: var(--wa-border-width-s) dashed var(--wa-color-brand-border-loud);"
    ></wa-icon>
    <wa-icon
      name="face-smile"
      style="background: var(--wa-color-brand-fill-quiet); border: var(--wa-border-width-s) dashed var(--wa-color-brand-border-loud);"
    ></wa-icon>
    <wa-icon
      name="file"
      style="background: var(--wa-color-brand-fill-quiet); border: var(--wa-border-width-s) dashed var(--wa-color-brand-border-loud);"
    ></wa-icon>
    <wa-icon
      name="ruler-vertical"
      style="background: var(--wa-color-brand-fill-quiet); border: var(--wa-border-width-s) dashed var(--wa-color-brand-border-loud);"
    ></wa-icon>
  </div>

  <wa-divider></wa-divider>

  <div class="wa-cluster wa-gap-xl" style="align-items: start;">
    <wa-select label="Canvas" name="canvas" value="fixed">
      <wa-option value="fixed">fixed</wa-option>
      <wa-option value="auto">auto</wa-option>
      <wa-option value="square">square</wa-option>
      <wa-option value="roomy">roomy</wa-option>
    </wa-select>
    <wa-slider label="Size" min="0" max="4" value="2" with-markers style="flex: 1 1 14rem;">
      <span slot="reference">1.5rem</span>
      <span slot="reference">2rem</span>
      <span slot="reference">3rem</span>
      <span slot="reference">4rem</span>
      <span slot="reference">5rem</span>
    </wa-slider>
  </div>
</div>

<style>
  .canvas-demo-preview {
    margin-block-end: 1.5rem;
    font-size: 3rem;
  }
</style>

<script>
  (() => {
    const demo = document.querySelector('.canvas-demo');
    const preview = demo.querySelector('.canvas-demo-preview');
    const icons = preview.querySelectorAll('wa-icon');
    const sizes = ['1.5rem', '2rem', '3rem', '4rem', '5rem'];

    demo.querySelector('wa-select[name="canvas"]').addEventListener('change', event => {
      icons.forEach(icon => (icon.canvas = event.target.value));
    });
    demo.querySelector('wa-slider').addEventListener('input', event => {
      preview.style.fontSize = sizes[event.target.value];
    });
  })();
</script>
```

The `auto-width` attribute still works but is deprecated — prefer `canvas="auto"`, which renders the same way.

### Rotating & Flipping

Web Awesome supports [Font Awesome's rotation and flip utilities](https://docs.fontawesome.com/web/style/rotate/) for adjusting icon orientation. Use the `rotate` attribute to turn an icon by **any** number of degrees — not just the quarter-turns below — and the `flip` attribute to mirror it across the `x`, `y`, or `both` axes.

| Attribute | Value |
| --- | --- |
| \`rotate\` | \`90\` |
| \`rotate\` | \`180\` |
| \`rotate\` | \`270\` |
| \`flip\` | \`x\` |
| \`flip\` | \`y\` |
| \`flip\` | \`both\` |

Rotate by any angle — and combine `rotate` and `flip` on the same icon:

```html
<wa-icon name="snowboarding" style="font-size: 2em;"></wa-icon>
<wa-icon name="snowboarding" rotate="45" style="font-size: 2em;"></wa-icon>
<wa-icon name="snowboarding" rotate="135" style="font-size: 2em;"></wa-icon>
<wa-icon name="snowboarding" rotate="270" style="font-size: 2em;"></wa-icon>
<wa-icon name="snowboarding" flip="both" style="font-size: 2em;"></wa-icon>
<wa-icon name="snowboarding" rotate="45" flip="x" style="font-size: 2em;"></wa-icon>
```

### Animating

Web Awesome supports [Font Awesome's animation utilities](https://docs.fontawesome.com/web/style/animate/) for adding visual interest to icons. To select different types of animations, use the `animation` attribute when you reference an icon.

Every animation accepts the same timing controls — `--animation-delay`, `--animation-direction`, `--animation-duration`, `--animation-iteration-count`, and `--animation-timing` — plus the animation-specific custom properties shown in each example below. All animations respect `prefers-reduced-motion` (see [Accessibility Considerations](#accessibility-considerations)).

#### Beat

Use the `beat` animation to scale an icon up or down. This is useful for grabbing attention or for use with health/heart-centric icons.

```html
<wa-icon name="heart" animation="beat" label="Beating Heart" style="font-size: 2em;"></wa-icon>
<wa-icon name="circle-plus" animation="beat" label="Beating Circle Plus" style="font-size: 2em;"></wa-icon>
<!-- Use --beat-scale to control how far it grows -->
<wa-icon
  name="face-grin-hearts"
  animation="beat"
  label="Beating Smiley"
  style="font-size: 2em; --beat-scale: 1.5;"
></wa-icon>
```

#### Fade

Use the `fade` animation to fade an icon in and out visually to grab attention in a subtle (or not so subtle) way.

```html
<wa-icon name="triangle-exclamation" animation="fade" label="Fading Warning" style="font-size: 2em;"></wa-icon>
<wa-icon name="skull-crossbones" animation="fade" label="Fading Danger" style="font-size: 2em;"></wa-icon>
<wa-icon name="cloud-arrow-down" animation="fade" label="Fading Download" style="font-size: 2em;"></wa-icon>
<!-- Use --fade-opacity to set how faint it fades (and --animation-duration the pace) -->
<wa-icon
  name="i-cursor"
  animation="fade"
  label="Fading Cursor"
  style="font-size: 2em; --animation-duration: 2s; --fade-opacity: 0.6;"
></wa-icon>
```

#### Beat-Fade

Use the `beat-fade` animation to grab attention by visually scaling and pulsing an icon in and out.

```html
<wa-icon name="person-digging" animation="beat-fade" label="Beat-Fading Construction" style="font-size: 2em;"></wa-icon>
<wa-icon name="circle-exclamation" animation="beat-fade" label="Beat-Fading Alert" style="font-size: 2em;"></wa-icon>
<!-- Stronger pulse: lower --beat-fade-opacity, higher --beat-fade-scale -->
<wa-icon
  name="square-exclamation"
  animation="beat-fade"
  label="Beat-Fading Alert"
  style="font-size: 2em; --beat-fade-opacity: 0.1;--beat-fade-scale: 1.25"
></wa-icon>
<!-- Subtler pulse -->
<wa-icon
  name="circle-info"
  animation="beat-fade"
  label="Beat-Fading Info"
  style="font-size: 2em; --beat-fade-opacity: 0.67;--beat-fade-scale: 1.075"
></wa-icon>
```

#### Bounce

Use the `bounce` animation to grab attention by visually bouncing an icon up and down.

```html
<wa-icon name="volleyball" animation="bounce" label="Bouncing Volleyball" style="font-size: 2em;"></wa-icon>

<!-- bounce with extra rebound and "squish" on landing -->
<wa-icon
  name="basketball"
  animation="bounce"
  label="Bouncing Basketball"
  style="font-size: 2em; --bounce-land-scale-x: 1.2;--bounce-land-scale-y: .8;--bounce-rebound: 5px;"
></wa-icon>

<!-- bounce animation with no "squish" -->
<wa-icon
  name="frog"
  animation="bounce"
  label="Bouncing Frog"
  style="font-size: 2em; --bounce-start-scale-x: 1; --bounce-start-scale-y: 1; --bounce-jump-scale-x: 1; --bounce-jump-scale-y: 1; --bounce-land-scale-x: 1; --bounce-land-scale-y: 1;"
></wa-icon>

<!-- bounce animation with no "squish" or "rebound" -->
<wa-icon
  name="envelope"
  animation="bounce"
  label="Bouncing Envelope"
  style="font-size: 2em; --bounce-start-scale-x: 1;--bounce-start-scale-y: 1;--bounce-jump-scale-x: 1;--bounce-jump-scale-y: 1;--bounce-land-scale-x: 1;--bounce-land-scale-y: 1;--bounce-rebound: 0;"
></wa-icon>
```

#### Flip

Use the `flip` animation to rotate an icon in 3D space. By default, flip rotates an icon about the Y axis 180 degrees. Flipping is helpful for transitions, processing states, or for using physical objects that one flips in the real world.

```html
<wa-icon name="compact-disc" animation="flip" label="Flipping Compact Disc" style="font-size: 2em;"></wa-icon>
<wa-icon name="camera-rotate" animation="flip" label="Flipping Camera Rotate" style="font-size: 2em;"></wa-icon>
<wa-icon name="compact-disc" animation="flip" label="Flipping Disc" style="font-size: 2em;"></wa-icon>
<!-- Set the flip axis with --flip-x / --flip-y -->
<wa-icon
  name="scroll"
  animation="flip"
  label="Flipping Scroll"
  style="font-size: 2em; --flip-x: 1; --flip-y: 0"
></wa-icon>
<!-- Slow it down with --animation-duration -->
<wa-icon
  name="money-check-dollar"
  animation="flip"
  label="Flipping Money Check Dollar"
  style="font-size: 2em; --animation-duration: 3s;"
></wa-icon>
```

#### Flip 360

Use the `flip-360` animation to flip an icon all the way around in one smooth rotation — an extension of `flip` that gives it some extra oomph. It shares the same `--flip-x`, `--flip-y`, and `--flip-z` axis properties, plus `--flip-angle`, `--flip-anticipation-scale`, and `--flip-overshoot`.

```html
<wa-icon name="compact-disc" animation="flip-360" label="Flipping Compact Disc" style="font-size: 2em;"></wa-icon>
<wa-icon name="camera-rotate" animation="flip-360" label="Flipping Camera Rotate" style="font-size: 2em;"></wa-icon>
<!-- Set the flip axis with --flip-x / --flip-y -->
<wa-icon
  name="scroll"
  animation="flip-360"
  label="Flipping Scroll"
  style="font-size: 2em; --flip-x: 1; --flip-y: 0;"
></wa-icon>
<!-- Slow it down with --animation-duration -->
<wa-icon
  name="compact-disc"
  animation="flip-360"
  label="Flipping Compact Disc"
  style="font-size: 2em; --animation-duration: 3s;"
></wa-icon>
```

#### Shake

Use the `shake` animation to grab attention or note that something is not allowed by shaking an icon back and forth.

```html
<wa-icon name="bell" animation="shake" label="Shaking Bell" style="font-size: 2em;"></wa-icon>
<wa-icon name="lock" animation="shake" label="Shaking Lock" style="font-size: 2em;"></wa-icon>
<wa-icon name="stopwatch" animation="shake" label="Shaking Stopwatch" style="font-size: 2em;"></wa-icon>
<wa-icon name="bomb" animation="shake" label="Shaking Bomb" style="font-size: 2em;"></wa-icon>
```

#### Spin

Use the `spin` animation to get any icon to rotate, and use `spin-pulse` to have it rotate with eight steps. Use `spin-reverse` to rotate counter-clockwise. This works especially well with `spinner` and everything in the spinner icons category.

```html
<wa-icon name="sync" animation="spin" label="Spinning Sync" style="font-size: 2em;"></wa-icon>
<wa-icon name="circle-notch" animation="spin" label="Spinning Circle Notch" style="font-size: 2em;"></wa-icon>
<wa-icon name="cog" animation="spin" label="Spinning Cog" style="font-size: 2em;"></wa-icon>
<wa-icon name="cog" animation="spin-reverse" label="Reverse Spinning Cog" style="font-size: 2em;"></wa-icon>
<wa-icon name="spinner" animation="spin-pulse" label="Pulse Spinning Spinner" style="font-size: 2em;"></wa-icon>
<wa-icon
  name="spinner"
  animation="spin-pulse"
  label="Pulse Spinning Spinner"
  style="font-size: 2em; --animation-direction: reverse"
></wa-icon>

<!-- spin a set number of times, then stop -->
<wa-icon
  name="compact-disc"
  animation="spin"
  label="Spinning Compact Disc"
  style="font-size: 2em; --animation-duration: 3s; --animation-iteration-count: 5; --animation-timing: ease-in-out;"
></wa-icon>
```

#### Spin Snap

Use `spin-snap` to rotate in distinct steps with a pause on each, like a clock's second hand. `spin-snap-4` stops at four positions and `spin-snap-8` at eight. Unlike `spin-pulse` — a continuous eight-step rotation — the snap animations ease into each stop. Add `--animation-direction: reverse` to any of them to run counter-clockwise.

```html
<wa-icon name="gear" animation="spin-snap" label="Snapping Gear" style="font-size: 2em;"></wa-icon>
<wa-icon name="gear" animation="spin-snap-4" label="Snapping Gear, four stops" style="font-size: 2em;"></wa-icon>
<wa-icon name="gear" animation="spin-snap-8" label="Snapping Gear, eight stops" style="font-size: 2em;"></wa-icon>
<!-- Add --animation-direction: reverse to run counter-clockwise -->
<wa-icon
  name="gear"
  animation="spin-snap"
  label="Snapping Gear, reversed"
  style="font-size: 2em; --animation-direction: reverse;"
></wa-icon>
```

#### Buzz

Use the `buzz` animation for a fast, tight vibration with rapid decay — quick attention without being loud, like a phone buzzing on a table or an expiring timer. Set `--buzz-distance` to control how far it travels.

```html
<wa-icon name="bell" animation="buzz" label="Buzzing Bell" style="font-size: 2em;"></wa-icon>
<wa-icon name="mobile" animation="buzz" label="Buzzing Phone" style="font-size: 2em;"></wa-icon>
<!-- Use --buzz-distance to control how far it travels -->
<wa-icon
  name="triangle-exclamation"
  animation="buzz"
  label="Buzzing Warning"
  style="font-size: 2em; --buzz-distance: 9px;"
></wa-icon>
```

#### Float

Use the `float` animation for a slow, drifting motion — great for empty states, subtle attention, and adding a bit of playful lightness. Adjust `--float-height`, `--float-drift`, and `--float-tilt` to shape the motion.

```html
<wa-icon name="feather" animation="float" label="Floating Feather" style="font-size: 2em;"></wa-icon>
<wa-icon name="ghost" animation="float" label="Floating Ghost" style="font-size: 2em;"></wa-icon>
<!-- Use --float-height to control the rise (and --animation-duration the pace) -->
<wa-icon
  name="feather"
  animation="float"
  label="Floating Feather"
  style="font-size: 2em; --animation-duration: 2s; --float-height: 0.5em;"
></wa-icon>
```

#### Jello

Use the `jello` animation for a playful jiggle — great for calling attention to something new, fun, or interactive. Set `--jello-scale-x` and `--jello-scale-y` to control how far it deforms.

```html
<wa-icon name="cube" animation="jello" label="Jiggling Cube" style="font-size: 2em;"></wa-icon>
<wa-icon name="droplet" animation="jello" label="Jiggling Droplet" style="font-size: 2em;"></wa-icon>
<!-- Use --jello-scale-x to control how far it stretches -->
<wa-icon
  name="star"
  animation="jello"
  label="Jiggling Star"
  style="font-size: 2em; --animation-duration: 2s; --jello-scale-x: 1.3;"
></wa-icon>
```

#### Swing

Use the `swing` animation for a subtle dangle with a slow decay — great for things that physically dangle, like keys or a price tag. Set `--swing-angle` to control the peak rotation.

```html
<wa-icon name="bell" animation="swing" label="Swinging Bell" style="font-size: 2em;"></wa-icon>
<wa-icon name="key" animation="swing" label="Swinging Key" style="font-size: 2em;"></wa-icon>
<!-- Use --swing-angle to control the peak rotation -->
<wa-icon
  name="tag"
  animation="swing"
  label="Swinging Tag"
  style="font-size: 2em; --animation-duration: 2s; --swing-angle: 45deg;"
></wa-icon>
```

#### Wag

Use the `wag` animation, a cousin of `swing`, for a bottom-anchored wag — the top of the icon sways back and forth with a slow decay. Set `--wag-angle` to control the peak rotation.

```html
<wa-icon name="hand-pointer" animation="wag" label="Wagging Pointer" style="font-size: 2em;"></wa-icon>
<wa-icon name="hand-point-up" animation="wag" label="Wagging Finger" style="font-size: 2em;"></wa-icon>
<!-- Use --wag-angle to control the peak rotation -->
<wa-icon
  name="hand-point-right"
  animation="wag"
  label="Wagging Finger"
  style="font-size: 2em; --animation-duration: 2s; --wag-angle: 45deg;"
></wa-icon>
```

### Duotone

Duotone icons render on two layers — a primary and a secondary — that you can recolor and fade independently. By default both layers use `currentColor`, with the secondary layer at 40% opacity. These properties don't inherit, so set them directly on the icon.

| Property | Description | Default |
| --- | --- | --- |
| \`--primary-color\` | Color of the primary (foreground) layer | \`currentColor\` |
| \`--secondary-color\` | Color of the secondary (background) layer | \`currentColor\` |
| \`--primary-opacity\` | Opacity of the primary layer | \`1\` |
| \`--secondary-opacity\` | Opacity of the secondary layer | \`0.4\` |
| \`swap-opacity\` | Attribute that swaps the primary and secondary opacities | \`false\` |

```html
<div class="duotone-demo">
  <div class="duotone-demo-preview wa-cluster">
    <wa-icon family="duotone" name="palette" label="Palette"></wa-icon>
    <wa-icon family="duotone" name="crow" label="Crow"></wa-icon>
    <wa-icon family="duotone" name="campfire" label="Campfire"></wa-icon>
    <wa-icon family="duotone" name="cloud-sun" label="Cloud and sun"></wa-icon>
    <wa-icon family="duotone" name="bell" label="Bell"></wa-icon>
  </div>

  <wa-divider></wa-divider>

  <div class="wa-cluster wa-gap-xl duotone-demo-controls">
    <wa-color-picker label="Primary color"></wa-color-picker>
    <wa-color-picker label="Secondary color"></wa-color-picker>
    <wa-slider label="Primary opacity" min="0" max="1" step="0.1" value="1"></wa-slider>
    <wa-slider label="Secondary opacity" min="0" max="1" step="0.1" value="0.4"></wa-slider>
  </div>
</div>

<style>
  .duotone-demo-preview {
    justify-content: center;
    font-size: 3rem;
    min-height: 6rem;
    margin-block-end: 1.5rem;
  }
  .duotone-demo-controls {
    align-items: end;
  }
  .duotone-demo-controls wa-slider {
    flex: 1 1 10rem;
  }
</style>

<script>
  (() => {
    const demo = document.querySelector('.duotone-demo');
    const icons = demo.querySelectorAll('.duotone-demo-preview wa-icon');
    const [primary, secondary] = demo.querySelectorAll('wa-color-picker');
    const [primaryOpacity, secondaryOpacity] = demo.querySelectorAll('wa-slider');

    // Until the user picks a color, each layer stays on its default currentColor so it tracks
    // the color scheme. Opacity changes must not pin a color, or the icons freeze on toggle.
    let hasPrimaryColor = false;
    let hasSecondaryColor = false;

    const applyOpacity = () => {
      icons.forEach(icon => {
        icon.style.setProperty('--primary-opacity', primaryOpacity.value);
        icon.style.setProperty('--secondary-opacity', secondaryOpacity.value);
      });
    };

    primary.addEventListener('input', () => {
      hasPrimaryColor = true;
      icons.forEach(icon => icon.style.setProperty('--primary-color', primary.value));
    });
    secondary.addEventListener('input', () => {
      hasSecondaryColor = true;
      icons.forEach(icon => icon.style.setProperty('--secondary-color', secondary.value));
    });
    primaryOpacity.addEventListener('input', applyOpacity);
    secondaryOpacity.addEventListener('input', applyOpacity);

    // Keep the unedited color pickers showing the page's text color so their swatches match the
    // icons' default currentColor — and re-probe when the scheme changes so they don't go stale.
    const syncColorDefaults = () => {
      const probe = document.createElement('span');
      demo.appendChild(probe);
      const textColor = getComputedStyle(probe).color;
      probe.remove();
      if (!hasPrimaryColor) primary.value = textColor;
      if (!hasSecondaryColor) secondary.value = textColor;
    };

    customElements.whenDefined('wa-color-picker').then(syncColorDefaults);
    document.addEventListener('color-scheme-settled', syncColorDefaults);
    const preview = demo.closest('.code-example-preview');
    if (preview) {
      new MutationObserver(syncColorDefaults).observe(preview, { attributes: true, attributeFilter: ['class'] });
    }
  })();
</script>
```

Duotone icons can be unlocked by [providing a valid Font Awesome Kit code](https://webawesome.com/docs/#using-font-awesome-kit-codes).

### Swap Duotone Opacity

For duotone icons, you can swap the primary and secondary opacity values using the `swap-opacity` attribute. This is useful when you want to emphasize the secondary layer of the icon.

```html
<div class="wa-stack">
  <div class="wa-cluster" style="font-size: 1.5em;">
    <wa-icon family="duotone" name="home"></wa-icon>
    <wa-icon family="duotone" name="user"></wa-icon>
    <wa-icon family="duotone" name="envelope"></wa-icon>
    <wa-icon family="duotone" name="calendar"></wa-icon>
    <span style="font-size: 1rem;">Normal</span>
  </div>
  <div class="wa-cluster" style="font-size: 1.5em;">
    <wa-icon family="duotone" name="home" swap-opacity></wa-icon>
    <wa-icon family="duotone" name="user" swap-opacity></wa-icon>
    <wa-icon family="duotone" name="envelope" swap-opacity></wa-icon>
    <wa-icon family="duotone" name="calendar" swap-opacity></wa-icon>
    <span style="font-size: 1rem;">Swapped Opacity</span>
  </div>
</div>
```

### Font Awesome Pro+ Icons

If you're a [Font Awesome Pro+ customer](https://fontawesome.com/), you have access to whole packs of distinctive icons. Set the pack's `family` and `variant` like any other icon.

| Pack | Family | Variant |
| --- | --- | --- |
| Chisel | \`chisel\` | \`regular\` |
| Etch | \`etch\` | \`solid\` |
| Graphite | \`graphite\` | \`thin\` |
| Jelly | \`jelly\` , jelly-duo, jelly-fill | \`regular\` |
| Mosaic | \`mosaic\` | \`solid\` |
| Notdog | \`notdog\` , notdog-duo | \`solid\` |
| Pixel | \`pixel\` | \`regular\` |
| Slab | \`slab\` , slab-press, slab-duo, slab-press-duo | \`regular\` |
| Thumbprint | \`thumbprint\` | \`light\` |
| Utility | \`utility\` , utility-duo, utility-fill | \`semibold\` |
| Vellum | \`vellum\` | \`solid\` |
| Whiteboard | \`whiteboard\` | \`semibold\` | Pro+ icons can be unlocked by [providing a valid Font Awesome Kit code](https://webawesome.com/docs/#using-font-awesome-kit-codes).
