Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelog App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSeparatorSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridData TableDescription ListDiffEvent CalendarGaugeJSON TreeKanbanKey ValueLevel MeterListMeterSparklineStatStepperTableTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputOTP InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip
ARC UI ARC Radiant Components
v3.2 Docs Components Tokens Synthesizer
Getting StartedFrameworksServer Rendering Design TokensThemingTheme SynthesizerTypographyUtilities All ComponentsAccessibilityBrowser SupportChangelogContributingStats App ShellAspect GridAuth ShellCenterClusterContainerDashboard GridDockFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkSpeed DialStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCalloutCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSeparatorSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridData TableDescription ListDiffEvent CalendarGaugeJSON TreeKanbanKey ValueLevel MeterListMeterSparklineStatStepperTableTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputOTP InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuGuided TourHover CardInline MessageLoading OverlayModalNotification PanelPopoverProgressProgress ToastSheetSnackbarSpotlightToastTooltip

Icon

Renders icons from Phosphor (1,500+) or Lucide (1,900+) by name, 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. ARC UI ships with two icon libraries built in. **Phosphor Icons** (phosphoricons.com) is the default — a flexible, consistent set of over 1,500 icons with a clean filled style that works well at all sizes. **Lucide** (lucide.dev) is also bundled as an alternative — a community fork of Feather Icons with over 1,900 stroke-based icons that pair well with lighter UI styles. Use the icon browser below to explore both libraries and click any icon to copy its name. 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 you need the full icon library as a single import (e.g. for an icon picker), you can still opt in: ```js import phosphor from '@arclux/arc-ui/icons/phosphor'; // loads all ~1,500 icons import lucide from '@arclux/arc-ui/icons/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 built-in icon packs: Phosphor (1,500+ filled) and Lucide (1,900+ stroke-based)
  • 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 (Phosphor is the default library) -->
<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';

// 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