@genarou/blazir-icons
v1.3.2
Published
A high-performance Svelte 5 icon library with smart caching, lazy loading, presets, variants, and a declarative effects system.
Maintainers
Readme
blazir-icons
A high-performance Svelte 5 icon library with smart caching, lazy loading, presets, variants, and a declarative effects system.
- 163 icons — original SVG artwork
- Svelte 5 runes —
$props,$derived,$effect - Smart LRU cache — referential stability, zero re-renders on stable props
- Lazy loading — per-icon code splitting via
import() - Vite plugin — automatic tree shaking, only used icons in the bundle
- Full TypeScript — autocomplete on every prop, icon name, preset, and variant
- Accessible —
aria-label,title,decorativesupport out of the box
Table of Contents
- Installation
- Quick Start
- How It Works
- Icon Names
- Props Reference
- Presets
- Variants
- Lazy Loading
- Effects System
- Actions System
- IconBadge
- CustomIcon
- Vite Plugin (Tree Shaking)
- Direct Icon Imports
- TypeScript
- CSS Custom Properties
- Accessibility Guide
- Real-World Examples
Installation
npm install @genarou/blazir-icons
# or
pnpm add @genarou/blazir-iconsPeer dependency: Svelte 5
Quick Start
<script>
import { Icon } from '@genarou/blazir-icons'
</script>
<Icon name="check" />
<Icon name="home" size={24} color="var(--primary)" />
<Icon name="settings" preset="muted" />
<Icon name="trash" variant="danger" />The CSS animation stylesheet is injected automatically on import. No manual CSS setup required.
How It Works
Architecture overview
<Icon> ← Public wrapper
│
├─ preset + variant → getPresetVariantMerge() (frozen, stable reference)
├─ user props → arePropsStable() check
│ ├─ all primitives → LRU cache (128 entries) — same config = same reference
│ └─ objects/actions → direct merge (no cache, but baseProps stays stable)
│
├─ lazy=false (default) → iconRegistry[name] (static import, zero latency)
└─ lazy=true → getLoadedIcon() || loadIcon() (dynamic import + skeleton)
<IconBase> ← SVG renderer
├─ receives merged IconProps
├─ applies mode (solid / outline / duotone)
├─ computes hover color, transitions, animations
├─ binds effects action to the <g> layer
└─ renders <svg> with full a11y attributesSmart Cache (LRU)
The cache operates in two layers:
Preset/Variant merge —
getPresetVariantMerge(preset, variant)returns the exact same frozen object reference for any given combination. Because$derivedtracks object identity, this prevents unnecessary re-renders when only the reference changed but the content is identical.Full props merge (128-entry LRU) — when all user props are primitives (strings, numbers, booleans), a deterministic structural key is built and the result is stored in an LRU cache. The next render with the same config returns the cached reference — Svelte's scheduler sees no change and skips the component update entirely.
Props containing objects (
effects,actions,attrs,parentHoverContext) bypass the global LRU and are merged directly. The preset/variant base remains stable regardless.
This design makes blazir-icons suitable for high-frequency render contexts like data grids, virtualized lists, and real-time dashboards.
Lazy Loading internals
When lazy is omitted (default), the icon component is resolved synchronously from the static registry — no async code, no skeleton, same behavior as a plain import.
When lazy={true}:
- Svelte checks
getLoadedIcon(name)— a synchronous in-memory cache of already-loaded modules. - If found, renders immediately (zero visible latency on subsequent navigations).
- If not found, sets
isLoading = true(shows a skeleton placeholder), callsloadIcon(name)(dynamicimport()), and updates the component when the module resolves. - If the
nameprop changes before the load completes, the stale result is discarded — no race conditions.
Actions diff bridge
The actions prop accepts an array of [actionFn, params] tuples. On update, the bridge diffs the new array against the previous one:
- If all action functions are the same references → only
update(newParams)is called. Internal state is preserved (e.g. tooltip position, IntersectionObserver). - If any function reference changed →
destroy()+recreate()for that action.
This is critical for stateful actions like tooltips or lazy-load observers that should not be torn down on every prop change.
Icon Names
Every icon has a direct string name and a typed alias via bzIcons.
<script>
import { Icon, bzIcons } from '@genarou/blazir-icons'
</script>
<!-- Direct string (plugin can tree-shake this) -->
<Icon name="check" />
<!-- Typed alias — full autocomplete, same result -->
<Icon name={bzIcons.Check} />Available bzIcons aliases
All 163 icons organized by category. Use the alias for TypeScript autocomplete or the name as a plain string.
Navigation & Layout
| Alias | name |
|---|---|
| bzIcons.Home | home |
| bzIcons.Dashboard | dashboard |
| bzIcons.DashboardOutline | dashboardOutline |
| bzIcons.Settings | settings |
| bzIcons.Search | search |
| bzIcons.Filter | filter |
| bzIcons.Menu | menu |
| bzIcons.Close | close |
| bzIcons.Plus | plus |
| bzIcons.Copy | copy |
| bzIcons.Rocket | rocket |
| bzIcons.Sidebar | sidebar |
| bzIcons.More | more |
Users & Auth
| Alias | name |
|---|---|
| bzIcons.User | user |
| bzIcons.UserTie | userTie |
| bzIcons.Team | team |
| bzIcons.Group | group |
| bzIcons.Supervisor | supervisor |
| bzIcons.Enterprise | enterprise |
| bzIcons.Lock | lock |
| bzIcons.LockOpen | lockOpen |
| bzIcons.Key | key |
| bzIcons.Logout | logout |
| bzIcons.Eye | eye |
| bzIcons.EyeOff | eyeOff |
| bzIcons.Shield | shield |
| bzIcons.Fingerprint | fingerprint |
| bzIcons.Contact | contact |
| bzIcons.Security | security |
Communication
| Alias | name |
|---|---|
| bzIcons.Email | email |
| bzIcons.EmailAnimated | emailAnimated |
| bzIcons.Phone | phone |
| bzIcons.Bell | bell |
| bzIcons.Send | send |
| bzIcons.Share | share |
| bzIcons.World | world |
| bzIcons.Chat | chat |
| bzIcons.Link | link |
Business & Finance
| Alias | name |
|---|---|
| bzIcons.Building | building |
| bzIcons.Handshake | handshake |
| bzIcons.Money | money |
| bzIcons.Wallet | wallet |
| bzIcons.Profit | profit |
| bzIcons.Safe | safe |
| bzIcons.Cost | cost |
| bzIcons.Exchange | exchange |
| bzIcons.Swap | swap |
| bzIcons.Bank | bank |
| bzIcons.Pay | pay |
| bzIcons.CreditCard | creditCard |
| bzIcons.Receipt | receipt |
| bzIcons.Buy | buy |
Charts & Data
| Alias | name |
|---|---|
| bzIcons.Chart | chart |
| bzIcons.ChartDocument | chartDocument |
| bzIcons.ChartSquare | chartSquare |
| bzIcons.ChartDoughnut | chartDoughnut |
| bzIcons.Table | table |
| bzIcons.List | list |
| bzIcons.ListDots | listDots |
| bzIcons.ListGroup | listGroup |
| bzIcons.TrendingDown | trendingDown |
| bzIcons.Database | database |
| bzIcons.Server | server |
Files & Documents
| Alias | name |
|---|---|
| bzIcons.File | file |
| bzIcons.Pdf | pdf |
| bzIcons.Excel | excel |
| bzIcons.ExcelAnimated | excelAnimated |
| bzIcons.Word | word |
| bzIcons.PowerPoint | powerPoint |
| bzIcons.Csv | csv |
| bzIcons.Xml | xml |
| bzIcons.Zip | zip |
| bzIcons.Png | png |
| bzIcons.Notes | notes |
| bzIcons.Book | book |
| bzIcons.Image | image |
| bzIcons.ImageAnimated | imageAnimated |
| bzIcons.Folder | folder |
| bzIcons.FolderShared | folderShared |
| bzIcons.Attachment | attachment |
| bzIcons.Save | save |
| bzIcons.Form | form |
| bzIcons.Print | print |
Calendar & Time
| Alias | name |
|---|---|
| bzIcons.Calendar | calendar |
| bzIcons.CalendarPlus | calendarPlus |
| bzIcons.CalendarEdit | calendarEdit |
| bzIcons.Timer | timer |
Arrows & Navigation
| Alias | name |
|---|---|
| bzIcons.ArrowRight | arrowRight |
| bzIcons.ArrowUp | arrowUp |
| bzIcons.ArrowUpDown | arrowUpDown |
| bzIcons.ArrowLeftAnimated | arrowLeftAnimated |
| bzIcons.ChevronDown | chevronDown |
| bzIcons.ChevronUpDown | chevronUpDown |
File Actions
| Alias | name |
|---|---|
| bzIcons.Download | download |
| bzIcons.DownloadAnimated | downloadAnimated |
| bzIcons.Upload | upload |
| bzIcons.UploadAnimated | uploadAnimated |
| bzIcons.UploadProgress | uploadProgress |
| bzIcons.FileUploadAnimated | fileUploadAnimated |
| bzIcons.Refresh | refresh |
States & Feedback
| Alias | name |
|---|---|
| bzIcons.Check | check |
| bzIcons.CheckOutline | checkOutline |
| bzIcons.CheckList | checkList |
| bzIcons.CircleCheck | circleCheck |
| bzIcons.Error | error |
| bzIcons.ErrorOutline | errorOutline |
| bzIcons.CircleExclamation | circleExclamation |
| bzIcons.CircleExclamationOutline | circleExclamationOutline |
| bzIcons.Warning | warning |
| bzIcons.CircleInfo | circleInfo |
| bzIcons.CircleInfoOutline | circleInfoOutline |
| bzIcons.CircleQuestion | circleQuestion |
| bzIcons.CircleQuestionOutline | circleQuestionOutline |
| bzIcons.Star | star |
| bzIcons.Favorites | favorites |
| bzIcons.Heart | heart |
| bzIcons.Reset | reset |
| bzIcons.Height | height |
| bzIcons.Alternate | alternate |
| bzIcons.Moon | moon |
| bzIcons.Sun | sun |
| bzIcons.Colors | colors |
Loading & Progress
| Alias | name |
|---|---|
| bzIcons.SpinnerDots | spinnerDots |
| bzIcons.Spinner | spinner |
Commerce & Sales
| Alias | name |
|---|---|
| bzIcons.Product | product |
| bzIcons.Bag | bag |
| bzIcons.POS | pos |
| bzIcons.Category | category |
| bzIcons.CategoryAdd | categoryAdd |
| bzIcons.CategorySearch | categorySearch |
| bzIcons.BoxAdd | boxAdd |
| bzIcons.Measure | measure |
| bzIcons.Box | box |
| bzIcons.Scan | scan |
| bzIcons.Cart | cart |
| bzIcons.Cards | cards |
Logistics & Transport
| Alias | name |
|---|---|
| bzIcons.Truck | truck |
| bzIcons.TruckReturn | truckReturn |
| bzIcons.Warehouse | warehouse |
| bzIcons.Location | location |
| bzIcons.LocationAnimated | locationAnimated |
Tools & Utilities
| Alias | name |
|---|---|
| bzIcons.AI | ai |
| bzIcons.Edit | edit |
| bzIcons.EditOutline | editOutline |
| bzIcons.Trash | trash |
| bzIcons.TrashOutline | trashOutline |
| bzIcons.Tags | tags |
| bzIcons.Tools | tools |
| bzIcons.ObjectGroup | objectGroup |
| bzIcons.Project | project |
Media & Devices
| Alias | name |
|---|---|
| bzIcons.Camera | camera |
| bzIcons.Desktop | desktop |
| bzIcons.Wifi | wifi |
| bzIcons.Power | power |
Cloud
| Alias | name |
|---|---|
| bzIcons.CloudAlert | cloudAlert |
| bzIcons.CloudCheck | cloudCheck |
| bzIcons.CloudDownload | cloudDownload |
Other
| Alias | name |
|---|---|
| bzIcons.Blaze | blaze |
| bzIcons.Earth | earth |
| bzIcons.Globe | globe |
| bzIcons.LightHub | lightHub |
| bzIcons.Sync | sync |
Props Reference
All props are optional. Every prop can be passed to <Icon> or <IconBase>.
Visual
| Prop | Type | Default | Description |
|---|---|---|---|
| name | IconName | — | Icon identifier |
| size | number \| string | 24 | Width and height. Accepts px, rem, em, token (sm, md, lg, etc.) or a plain number |
| color | string | currentColor | Fill or stroke color |
| stroke | string | — | Explicit stroke color (overrides color for stroke) |
| strokeWidth | number \| string | — | SVG stroke width |
| strokeLinecap | "round" \| "butt" \| "square" | — | SVG stroke-linecap attribute |
| strokeLinejoin | "round" \| "miter" \| "bevel" | — | SVG stroke-linejoin attribute |
| fill | string | — | Explicit fill color |
| mode | "solid" \| "outline" \| "duotone" | "solid" | Rendering mode |
| viewBox | string | "0 0 24 24" | SVG viewBox attribute |
| preserveAspectRatio | string | — | SVG preserveAspectRatio attribute |
| class | string | — | CSS class on the wrapper element |
| className | string | — | Alias for class |
| style | string | — | Inline style on the wrapper element |
| attrs | Record<string, any> | — | Arbitrary extra attributes forwarded to the <svg> element (excluding width/height) |
Size Tokens
| Token | Value |
|---|---|
| xs | 12px |
| sm | 16px |
| md | 20px |
| lg | 24px |
| xl | 32px |
| 2xl | 40px |
| 3xl | 48px |
<Icon name="check" size="sm" />
<Icon name="check" size={32} />
<Icon name="check" size="1.5rem" />Transform
| Prop | Type | Default | Description |
|---|---|---|---|
| rotate | number \| string | — | Rotation in degrees or CSS string |
| flipH | boolean | false | Flip horizontally |
| flipV | boolean | false | Flip vertically |
| nonScalingStroke | boolean | false | Keep stroke width fixed regardless of transform (vector-effect="non-scaling-stroke") |
<Icon name="arrow" rotate={45} />
<Icon name="arrow" flipH />
<Icon name="arrow" rotate={90} flipV />Animations
| Prop | Type | Default | Description |
|---|---|---|---|
| spin | boolean \| number \| string | false | Continuous rotation. true = 1s linear, number = duration in ms |
| pulse | boolean | false | Opacity + scale pulse |
| bounce | boolean | false | Vertical bounce |
| wiggle | boolean | false | Left-right rotation wiggle |
| heartbeat | boolean | false | Double-pulse heartbeat effect |
| elastic | boolean | false | Elastic scale pop |
| animationDuration | number \| string | — | Override animation duration (400, "400ms", "0.4s") |
| animationDelay | number \| string | — | Animation start delay |
| animationEasing | string | — | CSS easing function |
<Icon name="loadingDots" spin />
<Icon name="loadingDots" spin={800} />
<Icon name="bell" bounce animationDuration={600} />
<Icon name="heart" heartbeat animationDelay="200ms" />
<Icon name="star" pulse animationEasing="ease-in-out" />
<!-- Combine multiple animations -->
<Icon name="loadingRegular" spin pulse />Entry Transitions
| Prop | Type | Description |
|---|---|---|
| scaleIn | boolean | Animate in with a scale effect |
| fadeIn | boolean | Animate in with a fade effect |
| slideIn | boolean | Animate in with a slide effect |
| slideDirection | "up" \| "down" \| "left" \| "right" | Direction for slideIn |
| morphTo | "play" \| "pause" \| "menu" \| "close" \| "arrow" \| "check" | Morph the icon shape to a target state |
| chevronState | "open" \| "closed" \| "up" \| "down" \| "left" \| "right" | Rotate a chevron icon to indicate state |
| chevronOpen | boolean | Shorthand: true = chevronState="open" |
<!-- Animated menu toggle -->
<Icon name="hamburguer" morphTo={isOpen ? 'close' : 'menu'} />
<!-- Animated accordion chevron -->
<Icon name="chevronDown" chevronOpen={isExpanded} />
<!-- Entry animations -->
<Icon name="check" scaleIn />
<Icon name="warning" fadeIn />
<Icon name="bell" slideIn slideDirection="down" />Interaction
| Prop | Type | Default | Description |
|---|---|---|---|
| hoverColor | string | — | Color applied on hover |
| activeColor | string | — | Color applied on press/active. Priority: activeColor > hoverColor > color |
| disabled | boolean | false | Reduces opacity to 0.4 and disables all pointer events and hover effects |
| loading | boolean | false | Replaces the icon with a spinning circle until false. Reuses internal spin keyframe — zero extra weight |
| tooltip | string | — | Native browser tooltip. Shorthand for effects={{ tooltip: "..." }} |
| hoverSpeed | "instant" \| "fast" \| "normal" \| "slow" \| "sluggish" | "normal" | Semantic preset for hover transition speed |
| transitionMs | number \| string | 250 | Exact hover transition duration. Overrides hoverSpeed |
| transitionEasing | string | "ease" | CSS easing for hover transition |
| parentHoverContext | { hovered: boolean } | — | Trigger hover state from a parent element |
hoverSpeed presets
| Value | Duration |
|---|---|
| "instant" | 0ms |
| "fast" | 120ms |
| "normal" | 250ms ← default |
| "slow" | 400ms |
| "sluggish" | 600ms |
<!-- Hover color with speed preset -->
<Icon name="edit" hoverColor="var(--primary)" hoverSpeed="fast" />
<!-- Active/press color -->
<Icon name="heart" hoverColor="#f97316" activeColor="#dc2626" />
<!-- Disabled state -->
<Icon name="send" disabled />
<Icon name="save" disabled={!isFormValid} />
<!-- Loading state — auto spinner, no wrapper needed -->
<Icon name="save" loading={isSaving} />
<!-- Tooltip -->
<Icon name="info" tooltip="More information" />
<!-- Custom easing -->
<Icon name="bell" hoverColor="var(--primary)" transitionMs={350} transitionEasing="ease-in-out" />
<!-- Trigger icon hover when parent row is hovered -->
<script>
let hovered = $state(false)
const ctx = $derived({ hovered })
</script>
<tr onmouseenter={() => hovered = true} onmouseleave={() => hovered = false}>
<td><Icon name="edit" parentHoverContext={ctx} hoverColor="var(--primary)" /></td>
</tr>Compact Mode
Reduces visual weight of solid icons at small sizes by adjusting opacity.
| Prop | Type | Default | Description |
|---|---|---|---|
| compact | "off" \| "auto" \| "outline" \| "duotone" | "off" | Compact rendering mode |
| compactSizeThreshold | number | 20 | Size in px below which compact activates (when "auto") |
| compactFillOpacity | number | 0.15 | Fill opacity in compact mode |
| compactStrokeWidth | number \| string | — | Stroke width in compact mode |
<!-- Auto: switches to outline style below 20px -->
<Icon name="user" compact="auto" size={16} />
<!-- Always compact duotone -->
<Icon name="folder" compact="duotone" compactFillOpacity={0.2} />Accessibility
| Prop | Type | Default | Description |
|---|---|---|---|
| ariaLabel | string | Icon name | aria-label on the SVG |
| title | string | — | SVG <title> element (tooltip on hover in browsers) |
| titleId | string | — | id for the <title> element (for aria-labelledby) |
| decorative | boolean | false | Sets aria-hidden="true" — use when icon is purely decorative |
| testId | string | — | data-testid attribute |
<!-- Decorative icon next to a labeled button -->
<button>
<Icon name="download" decorative />
Download
</button>
<!-- Standalone meaningful icon -->
<Icon name="check" ariaLabel="Task completed" />
<!-- With visible tooltip -->
<Icon name="info" title="More information" ariaLabel="More information" />Lazy Loading Prop
| Prop | Type | Default | Description |
|---|---|---|---|
| lazy | boolean | false | Load the icon as a separate dynamic import, enabling per-icon code splitting. Shows a skeleton placeholder while loading. |
<!-- Eager (default) — bundled with registry -->
<Icon name="check" />
<!-- Lazy — separate chunk, skeleton while loading -->
<Icon name="check" lazy />Presets
Presets apply a predefined set of props in one shot. Define colors, sizes, and behaviors using your CSS design tokens.
<Icon name="check" preset="success" />
<Icon name="home" preset="nav" />
<Icon name="plus" preset="button" />| Preset | Properties |
|---|---|
| primary | color: var(--primary), hoverColor: var(--primary-hover) |
| secondary | color: var(--secondary), hoverColor: var(--secondary-foreground) |
| accent | color: var(--accent-color), hoverColor: var(--accent-hover) |
| success | color: var(--success-color), hoverColor: var(--success-hover) |
| warning | color: var(--warning-color), hoverColor: var(--warning-hover) |
| danger | color: var(--danger-color), hoverColor: var(--danger-hover) |
| muted | color: var(--icon-fg, var(--ui-muted-fg)), hover → foreground |
| nav | size: 24, nav colors, subtle scale on hover |
| sidebar | size: 18, sidebar colors, scale on hover |
| button | size: 20, currentColor, cursor pointer, scale on hover |
| badge | size: 16, compact auto |
| hero | size: 48, primary color, bounce on hover |
| loading | spin: true, size: 24, primary color |
Props passed directly always override preset values.
<!-- preset sets size=24, but size={32} wins -->
<Icon name="check" preset="nav" size={32} />
<!-- preset + variant combination -->
<Icon name="trash" preset="button" variant="danger" />Variants
Variants apply a color scheme without touching size or behavior. Combine with presets for full control.
<Icon name="check" preset="button" variant="success" />| Variant | Color token |
|---|---|
| primary | var(--primary) |
| secondary | var(--secondary) |
| accent | var(--accent-color) |
| success | var(--success-color) |
| warning | var(--warning-color) |
| danger | var(--danger-color) |
| muted | var(--icon-fg, var(--ui-muted-fg)) |
| ghost | var(--ui-muted-fg) |
Lazy Loading
By default icons load eagerly (zero latency, no skeletons). Add lazy to defer loading and enable per-icon code splitting.
<!-- Eager (default) — same bundle chunk as always -->
<Icon name="check" />
<!-- Lazy — loaded on first render, skeleton shown while loading -->
<Icon name="check" lazy />Manual preload
Preload a set of icons before they are needed (e.g. on route anticipation):
import { preloadIcons } from '@genarou/blazir-icons'
// Runs in background via requestIdleCallback
preloadIcons(['check', 'home', 'settings', 'user'])Programmatic load
import { loadIcon, getLoadedIcon } from '@genarou/blazir-icons'
// Async load + cache
const Check = await loadIcon('check')
// Synchronous lookup (returns null if not yet loaded)
const Cached = getLoadedIcon('check')Effects System
Declarative interactive effects applied via the effects prop. All effects respect prefers-reduced-motion.
<Icon
name="settings"
effects={{ spinOnHover: true, cursor: 'pointer' }}
/>
<Icon
name="trash"
effects={{ wiggleOnHover: true, elasticOnClick: true }}
/>
<Icon
name="heart"
effects={{ heartbeatOnHover: true, hoverScale: 1.15 }}
/>IconEffectOptions
| Option | Type | Description |
|---|---|---|
| spinOnHover | boolean | Spin on mouse enter |
| bounceOnHover | boolean | Bounce on mouse enter |
| wiggleOnHover | boolean | Wiggle on mouse enter |
| slideOnHover | "up" \| "down" \| "left" \| "right" | Slide translate on hover |
| morphOnHover | "play" \| "pause" \| "menu" \| "close" \| "arrow" \| "check" | Morph shape on hover |
| elasticOnClick | boolean | Elastic scale pop on click |
| heartbeatOnActive | boolean | Heartbeat on mousedown |
| heartbeatOnHover | boolean | Heartbeat on hover |
| pulse | boolean | Continuous pulse |
| hoverScale | number | Scale factor on hover (1.1 = 110%) |
| pressScale | number | Scale factor on press |
| rotateOnHover | number | Degrees to rotate on hover |
| transitionMs | number | Transition duration in ms |
| easing | string | CSS easing function |
| cursor | string | CSS cursor on hover |
| tooltip | string | Native title tooltip |
| focusRing | boolean | Show visible focus ring |
| kbFocusAttr | string | Data attribute set on keyboard focus |
Using iconEffects as a Svelte action
For advanced cases where you need to apply effects to a custom element:
<script>
import { iconEffects } from '@genarou/blazir-icons'
</script>
<button use:iconEffects={{ spinOnHover: true, hoverScale: 1.1 }}>
Click me
</button>Actions System
Pass Svelte actions to the icon wrapper via the actions prop. Actions are diffed on update — state is preserved when params change.
<script>
import { Icon } from '@genarou/blazir-icons'
import { tooltip } from '$lib/actions/tooltip'
import { lazyLoad } from '$lib/actions/lazy'
let opts = $state({ text: 'Save file' })
</script>
<Icon
name="save"
actions={[[tooltip, opts], [lazyLoad]]}
/>Each entry in actions is a tuple [actionFn, params?]. When params change, update() is called. When the action function itself changes, the action is destroyed and recreated.
IconBadge
IconBadge wraps any icon with an absolute-positioned notification badge. Zero weight unless imported.
<script>
import { IconBadge } from '@genarou/blazir-icons'
</script>
<!-- Dot (boolean) -->
<IconBadge name="bell" badge />
<!-- Count -->
<IconBadge name="bell" badge={5} />
<!-- Text -->
<IconBadge name="chat" badge="!" />
<!-- Custom color and size -->
<IconBadge name="bell" badge={12} badgeColor="#f59e0b" badgeSize={18} />
<!-- Position (default: top-right) -->
<IconBadge name="bell" badge={3} badgePosition="top-left" />IconBadge props
Accepts all Icon props plus:
| Prop | Type | Default | Description |
|---|---|---|---|
| badge | boolean \| number \| string | — | true = dot · number/string = label |
| badgeColor | string | #ef4444 | Badge background color |
| badgeSize | number | 8 (dot) / 16 (label) | Badge diameter in px |
| badgePosition | "top-right" \| "top-left" \| "bottom-right" \| "bottom-left" | "top-right" | Corner placement |
badge={false}or omittingbadgerenders the icon directly without any wrapper element — no DOM overhead.
CustomIcon
Render any custom SVG string using the same IconBase engine — all effects, transitions, hover colors, animations and a11y props work out of the box.
<script>
import { CustomIcon } from '@genarou/blazir-icons'
const logoSvg = `<path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/>`
</script>
<!-- Same API as Icon — all props supported -->
<CustomIcon svgContent={logoSvg} size={32} color="var(--primary)" />
<!-- With hover and effects -->
<CustomIcon
svgContent={logoSvg}
hoverColor="#6366f1"
hoverSpeed="fast"
effects={{ hoverScale: 1.1 }}
/>
<!-- With animations -->
<CustomIcon svgContent={logoSvg} spin pulse />
<!-- Custom viewBox for non-24x24 SVGs -->
<CustomIcon svgContent={logoSvg} viewBox="0 0 48 48" size={48} />CustomIcon props
| Prop | Type | Default | Description |
|---|---|---|---|
| svgContent | string | required | Raw SVG inner markup (paths, circles, etc. — not the <svg> tag itself) |
| viewBox | string | "0 0 24 24" | ViewBox for the SVG container |
| + all IconProps | | | Every prop from the standard Icon is supported |
The content is rendered via
{@html}. For staticsvgContent(most common case) the cost is a singleinnerHTMLassignment at mount — identical to any other icon. AllIconBaseeffects run on the containing<g>layer.
Vite Plugin (Tree Shaking)
Without the plugin, all 152 icons are included in your bundle. With the plugin, only the icons you statically reference are bundled.
// vite.config.ts
import { blazirIconsPlugin } from '@genarou/blazir-icons/plugin'
import { svelte } from '@sveltejs/vite-plugin-svelte'
export default {
plugins: [
blazirIconsPlugin(),
svelte(),
]
}The plugin scans your source files at build time, detects static name="..." values, and generates a minimal registry.
<!-- Detected statically → only Check.svelte in bundle -->
<Icon name="check" />
<!-- Also detected statically -->
<Icon name={"home"} />
<!-- Dynamic → cannot detect → falls back to full registry (safe) -->
<Icon name={bzIcons.User} />
<Icon name={someVariable} />Plugin Options
blazirIconsPlugin({
// Root directory to scan. Default: Vite's config.root
root: './src',
// File extensions to include in scan
extensions: ['.svelte', '.ts', '.tsx', '.js', '.jsx'],
})Bundle size comparison
| Scenario | Bundle (gzip) | |---|---| | No plugin — all 163 icons | ~11 KB | | With plugin — 10 static icons | ~1–2 KB | | With plugin — dynamic names detected | ~11 KB (safe fallback) |
Direct Icon Imports
Import a single icon component directly for maximum tree shaking without the plugin:
import Check from '@genarou/blazir-icons/icons/Check'
import Home from '@genarou/blazir-icons/icons/Home'
import Settings from '@genarou/blazir-icons/icons/Settings'Use them as regular Svelte components. All IconProps are supported, but presets and variants are not applied automatically.
<Check size={20} color="var(--success-color)" />
<Home size={24} hoverColor="var(--primary)" />TypeScript
Full type coverage on all props and icon names.
import type { IconProps, IconName, IconMode } from '@genarou/blazir-icons'
import type { IconEffectOptions } from '@genarou/blazir-icons'
import type { BzIconKey } from '@genarou/blazir-icons'
// Typed icon name
const icon: IconName = 'check'
// Typed effect options
const effects: IconEffectOptions = {
spinOnHover: true,
hoverScale: 1.1,
}
// Typed bzIcons alias
const key: BzIconKey = 'Check'Extending the registry
import { iconRegistry } from '@genarou/blazir-icons'
// Autocomplete on all registry keys
type MyIconName = keyof typeof iconRegistryCSS Custom Properties
Customize animations globally via CSS variables.
| Variable | Default | Description |
|---|---|---|
| --bz-icon-bounce-amt | 18% | Bounce height |
| --bz-icon-pulse-scale | 1.04 | Pulse scale factor |
| --bz-icon-ring | primary | Focus ring color |
| --bz-icon-wiggle-angle | 3deg | Wiggle rotation amount |
| --bz-icon-slide-distance | 8px | Slide effect distance |
| --bz-icon-size | set by component | Icon size (set automatically) |
/* globals.css */
:root {
--bz-icon-bounce-amt: 24%;
--bz-icon-wiggle-angle: 5deg;
}Accessibility Guide
<!-- Decorative icon — hidden from screen readers -->
<button>
<Icon name="trash" decorative />
Delete item
</button>
<!-- Meaningful standalone icon -->
<Icon name="warning" ariaLabel="Warning: unsaved changes" />
<!-- With visible tooltip -->
<Icon name="info" title="More information" ariaLabel="More information" />
<!-- In a labeled group -->
<div aria-label="Status">
<Icon name="circleCheck" decorative />
<span>All systems operational</span>
</div>Real-World Examples
Sidebar navigation item
<script>
import { Icon } from '@genarou/blazir-icons'
export let active = false
export let label = ''
export let icon = 'home'
</script>
<a class="nav-item" class:active>
<Icon
name={icon}
preset="sidebar"
color={active ? 'var(--primary)' : undefined}
effects={{ hoverScale: 1.08 }}
decorative
/>
<span>{label}</span>
</a>Loading button
<script>
import { Icon } from '@genarou/blazir-icons'
let saving = $state(false)
async function submit() {
saving = true
await doWork()
saving = false
}
</script>
<!-- The icon swaps to a spinner automatically while saving -->
<button onclick={submit} disabled={saving}>
<Icon name="save" loading={saving} decorative />
{saving ? 'Saving...' : 'Save'}
</button>Animated accordion chevron
<script>
import { Icon } from '@genarou/blazir-icons'
let open = $state(false)
</script>
<button onclick={() => open = !open}>
Details
<Icon name="chevronRight" chevronOpen={open} preset="muted" decorative />
</button>Password visibility toggle
<script>
import { Icon } from '@genarou/blazir-icons'
let visible = $state(false)
</script>
<div class="input-wrapper">
<input type={visible ? 'text' : 'password'} />
<button
onclick={() => visible = !visible}
aria-label={visible ? 'Hide password' : 'Show password'}
>
<Icon
name={visible ? 'eyeOff' : 'eye'}
preset="muted"
effects={{ hoverScale: 1.1, cursor: 'pointer' }}
decorative
/>
</button>
</div>Notification bell with badge
<script>
import { IconBadge } from '@genarou/blazir-icons'
let count = $state(0)
</script>
<button aria-label="Notifications ({count} unread)">
<IconBadge
name="bell"
size={22}
badge={count > 0 ? count : false}
effects={{ wiggleOnHover: true, cursor: 'pointer' }}
decorative
/>
</button>Table row with hover-revealed actions
<script>
import { Icon } from '@genarou/blazir-icons'
let hovered = $state(false)
const ctx = $derived({ hovered })
</script>
<tr
onmouseenter={() => hovered = true}
onmouseleave={() => hovered = false}
>
<td>{row.name}</td>
<td class="actions">
<Icon name="edit" parentHoverContext={ctx} hoverColor="var(--primary)" preset="button" ariaLabel="Edit row" />
<Icon name="trash" parentHoverContext={ctx} hoverColor="var(--danger-color)" preset="button" ariaLabel="Delete row" />
</td>
</tr>Dynamic status icon
<script>
import { Icon } from '@genarou/blazir-icons'
import type { IconName } from '@genarou/blazir-icons'
type Status = 'success' | 'warning' | 'error' | 'loading'
const iconMap: Record<Status, IconName> = {
success: 'circleCheck',
warning: 'warning',
error: 'error',
loading: 'loadingDots',
}
export let status: Status = 'loading'
</script>
<Icon
name={iconMap[status]}
variant={status === 'loading' ? 'muted' : status}
spin={status === 'loading'}
size={18}
ariaLabel="Status: {status}"
/>Preloading icons on route change (SvelteKit)
// src/routes/dashboard/+page.ts
import { preloadIcons } from '@genarou/blazir-icons'
export const load = async () => {
// Icons are prefetched in background while page data loads
preloadIcons(['chart', 'table', 'user', 'settings', 'logout', 'bell'])
return {}
}Custom element with effects action
<script>
import { iconEffects } from '@genarou/blazir-icons'
import Check from '@genarou/blazir-icons/icons/Check'
</script>
<div
class="status-chip"
use:iconEffects={{ pulse: true, hoverScale: 1.05, cursor: 'pointer' }}
>
<Check size={14} color="var(--success-color)" decorative />
Active
</div>