site logo SVELTE ANIMATED ICON

Icon Components

The props every generated per-icon component accepts (and how variant selects the embedded SVG).

Every generated icon (Gear, Heart, ArrowRight, …) is a thin Svelte component that embeds its variant SVGs and forwards the rest to AnimatedIcon.

What a generated component looks like

<!-- src/lib/phosphor/icons/Acorn.svelte (auto-generated) -->
<script lang="ts">
  import AnimatedIcon from '../../core/AnimatedIcon.svelte';

  const VARIANTS: Record<string, string> = {
    regular: `<g fill="currentColor"><path d="M216,112v16c0,53-88,88-88,112…" fill="none" stroke="currentColor" …/></g>`,
    light:   `<g fill="currentColor"><path d="…" stroke-width="12"/></g>`,
    fill:    `<g fill="currentColor"><path d="M232,104a56.06,56.06,0,0,0-56-56…"/></g>`
  };

  interface Props {
    variant?: string;
    [key: string]: unknown;
  }

  let { variant = 'regular', ...rest }: Props = $props();
</script>

<AnimatedIcon svg={VARIANTS[variant]} {...rest} />

You don’t write these by hand. The codegen pipeline produces them - see Codegen Pipeline for how.

Props

A per-icon component exposes everything AnimatedIcon does, plus the variant prop.

PropTypeDefaultNotes
variantstringset per libraryPhosphor: 'regular' \| 'light' \| 'fill'. Remix: 'line' \| 'fill'. Flowbite/Hero: 'outline' \| 'solid'. Ion: 'outline' \| 'filled'.
templatestring'draw'Forwarded to AnimatedIcon.
sizenumber24Forwarded.
trigger'hover' \| 'mount' \| 'controlled''hover'Forwarded.
activebooleanfalseForwarded.
loopbooleanfalseForwarded.
speednumber1Forwarded.
easingstring \| nullnullForwarded.
classstring''Forwarded.

Because ...rest flows straight through, anything you can do with AnimatedIcon you can do with a per-icon component.

How variant selects the SVG

The codegen embeds all variants as raw markup strings in a VARIANTS object. Selecting one is just an object lookup:

VARIANTS[variant] // → string of inner SVG markup

No fetches, no dynamic imports, no runtime cost. Switching variants is free.

Why pass-through is the right pattern

If you ever need a prop a per-icon component doesn’t expose (for example, a custom field for analytics or a test hook), the [key: string]: unknown index signature in Props lets you pass arbitrary attributes straight through to AnimatedIcon’s wrapper. For anything beyond that, drop down to AnimatedIcon directly with your own SVG.

Generated vs. handwritten

The component files in src/lib/phosphor/icons/, src/lib/remix/icons/, src/lib/flowbite/icons/, src/lib/hero/icons/, and src/lib/ion/icons/ are overwritten by the codegen script. Don’t hand-edit them - your changes will be lost on the next node scripts/generate.js. To customize one icon permanently, copy it out of the generated set, edit it, and import the copy directly.

See Custom SVG Icons for the manual approach.