Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelog App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip
ARC UI ARC Radiant Components
v4.2 Docs Components Tokens Synthesizer
Getting StartedFrameworksServer Rendering Design TokensThemingTheme SynthesizerTypographyUtilities All ComponentsAccessibilityBrowser SupportChangelogContributingStats App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip

Icon

Renders icons by name from any registered library — Phosphor (1,500+) and Lucide (1,900+) ship in `@arclux/arc-ui-icons` — with one-line library switching and custom icon registration.

Components Icon
content static
<arc-icon>

Overview

Icon renders SVG icons from a centralized icon registry by name. When the `name` property is set, the component dynamically imports the matching icon file, parses it through a DOMParser-based sanitizer that strips all `<script>` elements and `on*` event handler attributes, and injects the cleaned SVG into the shadow DOM. Parsed SVGs are cached in a module-level Map for efficient re-renders. **Icons are loaded per-icon on demand.** Each of the 3,400+ icons is its own module (~500 bytes). When `<arc-icon name="star">` renders, only `star.js` is fetched — not the entire library. This means importing `arc-icon` adds **0KB** of icon data to your bundle upfront, and each icon you actually use costs only ~500 bytes. Bundlers automatically tree-shake unused icons out of production builds. **Icons live in their own package.** `@arclux/arc-ui-icons` carries two libraries: **Phosphor Icons** (phosphoricons.com), a consistent set of over 1,500 glyphs with a clean filled style that works at any size, and **Lucide** (lucide.dev), a community fork of Feather Icons with over 1,900 stroke-based glyphs that pair well with lighter UI. Use the icon browser below to explore both and click any icon to copy its name. Install it and import a pack. One line registers it, and if nothing else has been selected it becomes the active library — so `<arc-icon name="star">` works on the next line: ```js import '@arclux/arc-ui-icons/phosphor'; ``` Nothing is selected by default. Until a pack registers, every named icon renders its slot fallback and the registry logs one line saying so — it will not fail silently, but it will not guess either. Prior to v4 both packs were vendored inside `@arclux/arc-ui`, where they were 88% of the published files and 44% of the unpacked bytes of every install, icons or no icons. To switch libraries globally, use the `iconRegistry` API or the declarative `<arc-icon-library>` component: ```js // JavaScript API import { iconRegistry } from '@arclux/arc-ui'; iconRegistry.use('lucide'); // switch all icons to Lucide (no data loaded until icons render) ``` ```html <!-- Declarative (place anywhere in the document) --> <arc-icon-library name="lucide"></arc-icon-library> ``` You can also register custom icons on top of the active library. Custom icons are merged into the current set, so you can mix library icons with your own brand marks. Custom icons registered via `set()` resolve instantly with no network request: ```js iconRegistry.set({ 'my-logo': '<svg viewBox="0 0 24 24">...</svg>', 'custom-chart': '<svg viewBox="0 0 24 24">...</svg>', }); ``` If your app uses a handful of icons, skip the pack registration and import those glyphs directly. This pulls in one module per icon and no resolver at all: ```js import { iconRegistry } from '@arclux/arc-ui'; import check from '@arclux/arc-ui-icons/phosphor/check'; import x from '@arclux/arc-ui-icons/phosphor/x'; iconRegistry.set({ check, x }); ``` And if you need a whole library as a single import — an icon picker is the usual reason — that is still one line: ```js import phosphor from '@arclux/arc-ui-icons/all/phosphor'; // loads all ~1,500 icons import lucide from '@arclux/arc-ui-icons/all/lucide'; // loads all ~1,900 icons ``` Five size presets — xs (12px), sm (16px), md (20px), lg (24px), and xl (32px) — control the rendered dimensions. The component inherits color from its parent via `currentColor`, so icon color naturally follows the surrounding text or container styling. When no matching name is found in the registry, the component falls back to rendering its default slot, allowing you to pass inline SVGs or custom content directly. The `label` property controls accessibility behavior: when a label is provided, the icon wrapper receives `role="img"` and `aria-label` with the given text; when omitted, the icon is marked as `role="presentation"` with `aria-hidden="true"`, hiding it from assistive technology. This two-mode approach ensures decorative icons stay silent while meaningful icons are properly announced.

Guidelines

When to use

  • Provide a label for icons that convey meaning (e.g. status indicators, action icons)
  • Omit the label for purely decorative icons so they are hidden from screen readers
  • Use the size prop rather than CSS overrides to maintain consistent icon dimensions
  • Register custom icons via the iconRegistry before first render
  • Use currentColor inheritance by setting color on the parent element

When not to use

  • Do not pass unsanitized SVG strings from user input — while the component strips scripts, defense in depth is wise
  • Do not use the xl size for inline text icons; sm or md integrates better with body copy
  • Do not set both a name and slot content simultaneously — the name lookup takes precedence
  • Do not rely on the icon alone to communicate critical information; pair with visible text
  • Do not hardcode fill or stroke colors in registered SVGs — use currentColor so they adapt to context

Features

  • Per-icon lazy loading — only icons you use are fetched (~500 bytes each), 0KB upfront
  • Two icon packs in `@arclux/arc-ui-icons`: Phosphor (1,500+ filled) and Lucide (1,900+ stroke-based)
  • Registered, not bundled — core ships no icon data, and any library can register itself
  • One-line library switching via iconRegistry.use() or `<arc-icon-library>`
  • Custom icon registration — merge your own SVGs on top of any library (renders instantly)
  • Five size presets: xs (12px), sm (16px), md (20px), lg (24px), xl (32px)
  • Inherits color via currentColor for natural parent-driven styling
  • Slot fallback when no registry name matches, allowing inline SVG passthrough
  • Accessible role switching: `role="img"` with label, `role="presentation"` without
  • XSS-safe: strips <script> tags and on* event handlers from SVG content

Preview

Usage

<!-- Basic usage, once a pack is registered (see the Registry API tab) -->
<arc-icon name="star" size="sm"></arc-icon>
<arc-icon name="heart" size="md"></arc-icon>
<arc-icon name="gear" size="lg"></arc-icon>

<!-- Accessible icon with label -->
<arc-icon name="warning" size="md" label="Warning"></arc-icon>

<!-- Switch to Lucide globally -->
<arc-icon-library name="lucide"></arc-icon-library>
import { iconRegistry } from '@arclux/arc-ui';
import '@arclux/arc-ui-icons/lucide';

// Switch all icons to Lucide
iconRegistry.use('lucide');

// List all available icon names (async — loads manifest lazily)
const names = await iconRegistry.list();          // active library
const phosphor = await iconRegistry.list('phosphor'); // specific library

// Register custom icons (merged on top of active library)
iconRegistry.set({
  'my-logo': '<svg viewBox="0 0 24 24">...</svg>',
});

// Look up an icon by name (async — loads single icon lazily)
const svg = await iconRegistry.get('star'); // returns SVG string or null
import { Icon } from '@arclux/arc-ui-react';

export default function Example() {
  return (
    <>
      <Icon name="star" size="sm" />
      <Icon name="heart" size="md" />
      <Icon name="gear" size="lg" label="Settings" />
    </>
  );
}
<script setup>
import { Icon } from '@arclux/arc-ui-vue';
</script>

<template>
  <Icon name="star" size="sm" />
  <Icon name="heart" size="md" />
  <Icon name="gear" size="lg" />
</template>
<script>
  import { Icon } from '@arclux/arc-ui-svelte';
</script>

<Icon name="star" size="sm" />
<Icon name="heart" size="md" />
<Icon name="gear" size="lg" />
import { Component } from '@angular/core';
import { Icon } from '@arclux/arc-ui-angular';

@Component({
  imports: [Icon],
  template: `
    <arc-icon name="star" size="sm"></arc-icon>
    <arc-icon name="heart" size="md"></arc-icon>
    <arc-icon name="gear" size="lg"></arc-icon>
  `,
})
export class MyComponent {}
import { Icon } from '@arclux/arc-ui-solid';

export default function Example() {
  return (
    <>
      <Icon name="star" size="sm" />
      <Icon name="heart" size="md" />
      <Icon name="gear" size="lg" />
    </>
  );
}
import { Icon } from '@arclux/arc-ui-preact';

export default function Example() {
  return (
    <>
      <Icon name="star" size="sm" />
      <Icon name="heart" size="md" />
      <Icon name="gear" size="lg" />
    </>
  );
}
<!-- Auto-generated by @arclux/prism — do not edit manually -->
<!-- arc-icon — requires icon.css + base.css (or arc-ui.css) -->
<span class="arc-icon">
  <span
   class="icon"
   role="presentation"
   aria-label="Label"
   aria-hidden="true"
   >

   </span>
</span>
<!-- Auto-generated by @arclux/prism — do not edit manually -->
<!-- arc-icon — self-contained, no external CSS needed -->
<span class="arc-icon" style="display: inline-flex; align-items: center; justify-content: center; color: currentColor; vertical-align: middle">
  <span
   style="display: flex; align-items: center; justify-content: center; width: 100%; height: 100%"
   role="presentation"
   aria-label="Label"
   aria-hidden="true"
   >

   </span>
</span>

API

name string ''
Icon name to look up in the icon registry. When provided, renders the matching SVG. When empty, falls back to slotted content.
size 'xs' | 'sm' | 'md' | 'lg' | 'xl' 'sm'
Icon dimensions: xs (12px), sm (16px), md (20px), lg (24px), xl (32px).
label string ''
Accessibility label. When provided, sets role="img" and aria-label. When empty, sets role="presentation" and aria-hidden="true".

See Also