Icons
Icons come from the Hugeicons "Core Free" set, rendered as native Svelte components. The wrapper components under iconset/ are generated, not written by hand.
Using an icon
Import the icon directly from iconset/ by its Hugeicons name:
<script lang="ts">
import ToolboxIcon from '$lib/components/ui/icons/iconset/ToolboxIcon.svelte';
</script>
<ToolboxIcon size={16} />
Icon names match the export names from @hugeicons/core-free-icons — PascalCase, suffixed with Icon (e.g. PlusSignIcon, Delete02Icon, ToolboxIcon). Browse the available set on the Hugeicons site (free "stroke rounded" icons only — Pro icons aren't installed). If a name you expect isn't present under iconset/, the dev server/build simply hasn't run yet in this checkout; starting it once generates the full set.
Each generated component forwards to HugeiconsIcon and accepts the same props (minus icon, which is baked in):
| Prop | Type | Default | Description |
|---|---|---|---|
size | string | number | 24 | Icon width & height. |
color | string | currentColor | Stroke color. Prefer leaving unset and controlling via CSS color instead. |
strokeWidth | number | 2 | Set by the generated wrapper — pass the prop to override per usage. |
class | string | — | Forwarded class, same as any other component. |
...SVGAttributes | Any other standard SVG attribute (aria-hidden, onclick, …) is forwarded. |
Passing icons through props
Use the IconComponent type (resources/js/components/ui/icons/index.ts) whenever a component accepts an icon as a prop instead of hard-coding one — for example so a caller can choose which icon a button renders:
export type IconComponent = Component<Omit<HugeiconsProps, 'icon'>>;
<script lang="ts">
import type {IconComponent} from '$lib/components/ui/icons/index.js';
interface Props {
icon?: IconComponent;
}
const {icon: Icon}: Props = $props();
</script>
{#if Icon}
<Icon class="my-icon" />
{/if}
Button uses this exact pattern for its iconLeft / iconRight props (ui/button/Button.svelte) — pass the icon component reference itself, not a rendered element:
<script lang="ts">
import Button from '$lib/components/ui/button/Button.svelte';
import PlusSignIcon from '$lib/components/ui/icons/iconset/PlusSignIcon.svelte';
</script>
<Button iconLeft={PlusSignIcon}>Add</Button>
How generation works
.vite/vitePluginHugeicons.ts runs on buildStart (production build) and when the dev server starts (configureServer). For every exported *Icon from @hugeicons/core-free-icons, it writes one .svelte wrapper file into resources/js/components/ui/icons/iconset/:
<!-- Auto-generated by vitePluginHugeicons — do not edit. -->
<script lang="ts">
import {HugeiconsIcon, type HugeiconsProps, type IconSvgElement} from '@hugeicons/svelte';
const iconData: IconSvgElement = [ /* raw icon path data */ ];
let {...props}: HugeiconsProps = $props();
</script>
<HugeiconsIcon icon={iconData} strokeWidth={2} {...props} />
resources/js/components/ui/icons/iconset/is gitignored — the free set generates 4000+ files and is never checked in. It's (re)built automatically the first timenpm run dev/npm run buildruns (viabin/env).- Regeneration is skipped once a
.gen-versionmarker in the output directory matches the installed@hugeicons/core-free-iconsversion plus the plugin's ownPLUGIN_VERSION. BumpPLUGIN_VERSIONin the plugin if the generated file template changes, so every checkout regenerates. - Never hand-edit anything inside
iconset/— it's overwritten on the next generation and doesn't exist at all until the first dev/build run.