Skip to main content

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):

PropTypeDefaultDescription
sizestring | number24Icon width & height.
colorstringcurrentColorStroke color. Prefer leaving unset and controlling via CSS color instead.
strokeWidthnumber2Set by the generated wrapper — pass the prop to override per usage.
classstringForwarded class, same as any other component.
...SVGAttributesAny 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 time npm run dev / npm run build runs (via bin/env).
  • Regeneration is skipped once a .gen-version marker in the output directory matches the installed @hugeicons/core-free-icons version plus the plugin's own PLUGIN_VERSION. Bump PLUGIN_VERSION in 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.