Files
openchamber/packages/ui/src/components/icon
Bohdan Triapitsyn a3908232ae feat: render LSP tool output in chat
Adds expandable LSP tool rows with scan icon and stable file path display
Adds formatted/raw JSON output toggle and copy action
Improves compact LSP input formatting
2026-06-03 17:15:52 +03:00
..
2026-06-03 17:15:52 +03:00

Icon System

OpenChamber uses an SVG sprite-based icon system for performance. All icons are rendered via a single hidden SVG sprite injected into the DOM, referenced by <use href="#oc-icon-name"/>.

Usage

import { Icon } from "@/components/icon/Icon";

<Icon name="arrow-down-s" className="h-4 w-4" />
<Icon name="loader-4" className="size-4 animate-spin" />

Icon Names

Icons use kebab-case names based on Remixicon. To find an icon name:

  1. Start from the Remixicon component name: RiArrowDownSLine
  2. Remove Ri prefix → ArrowDownSLine
  3. Convert to kebab-case → arrow-down-s

Common suffixes:

  • Line / Fill are dropped from the sprite name
  • Numbers are preserved: RiChat4Linechat-4

Adding a New Icon

  1. Import and use it in your code: <Icon name="new-icon-name" />
  2. Run bun run icons:sprite to regenerate the sprite with the new icon
  3. The script scans packages/ui/src for all RiX usages and extracts SVG paths

If the icon doesn't exist in the sprite, the script will warn you.

Sizing

The Icon component does not have a size prop. Use Tailwind classes instead:

<Icon name="arrow-down-s" className="h-4 w-4" />   {/* 16px */}
<Icon name="arrow-down-s" className="size-5" />      {/* 20px */}
<Icon name="arrow-down-s" className="h-6 w-6" />     {/* 24px */}

Type Safety

import type { IconName } from "@/components/icon/icons";

const icon: IconName = "arrow-down-s"; // type-checked

Architecture

  • sprite.ts — Auto-generated SVG path data (run bun run generate-icon-sprite to regenerate)
  • Icon.tsx — The <Icon> component, injects sprite on first mount
  • icons.ts — TypeScript type IconName

The sprite is injected as a hidden <svg id="openchamber-icon-sprite"> element containing <symbol> elements. Each <Icon> renders <svg><use href="#oc-{name}"/></svg>.

Migration from @remixicon/react

Old:

import { RiArrowDownSLine } from "@remixicon/react";
<RiArrowDownSLine className="h-4 w-4" />

New:

import { Icon } from "@/components/icon/Icon";
<Icon name="arrow-down-s" className="h-4 w-4" />

If an icon is used as a component reference (not JSX):

// Old: const icon = RiStackLine; return <icon />;
// New: const icon: IconName = "stack"; return <Icon name={icon} />;