---
id: "packages/active-ui/dynamic-icon"
title: "DynamicIcon and Icons"
description: "A Lucide icon chosen by its name from data, and the small named icon set the composed components use."
url: "/packages/active-ui/dynamic-icon"
locale: "en"
revision: "a5bfbf1e75fcb31f"
---

# DynamicIcon and Icons

`DynamicIcon` renders a [Lucide](https://lucide.dev) icon by its name, for icons that come from
data, such as a navigation config. `Icons` is a fixed object of Lucide icons under short names
(`Icons.maximize`, `Icons.x`), as the composed components use them.

**Example: Icons by name, and the fixed set**

Client: Runs entirely in your browser. Source: `examples/ui/dynamic-icon.tsx`.

```tsx
// apps/docs/examples/ui/dynamic-icon.tsx
import {
  DynamicIcon,
  type IconName,
} from '@workspace/active-ui/components/composed/dynamic-icon';
import {Icons} from '@workspace/active-ui/components/composed/icons';

// Navigation as data: the icon is a name, as it would come from a config.
const NAVIGATION: {label: string; icon: IconName}[] = [
  {label: 'Dashboard', icon: 'LayoutDashboard'},
  {label: 'Participants', icon: 'Users'},
  {label: 'Settings', icon: 'Settings'},
];

const NAMED = Object.entries(Icons).filter(([name]) => name !== 'logo');

/**
 * Icons by name from data with `DynamicIcon`, and the fixed set `Icons`
 * that the composed components use, each under its name.
 */
export default function DynamicIconExample() {
  return (
    <div className="grid w-full max-w-2xl gap-8">
      <ul className="grid gap-2 text-sm">
        {NAVIGATION.map((item) => (
          <li key={item.label} className="flex items-center gap-2">
            <DynamicIcon name={item.icon} className="size-4" aria-hidden />
            {item.label}
          </li>
        ))}
      </ul>
      <ul className="grid grid-cols-2 gap-3 text-xs sm:grid-cols-4">
        {NAMED.map(([name, Icon]) => (
          <li key={name} className="flex items-center gap-2">
            <Icon className="size-4 shrink-0" aria-hidden />
            <code>{name}</code>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

## What the composition adds

- **Names that are checked**: `IconName` is every icon export of `lucide-react`, aliases
  included, and nothing else; an unknown name from data at runtime renders nothing instead of
  throwing.
- **`Icons.logo`** is a placeholder mark from the original template; replace it with your own.

`DynamicIcon` imports the whole icon set. Where the icon is known in your code, import it directly
from `lucide-react`.

## Usage

```tsx
import {DynamicIcon} from '@workspace/active-ui/components/composed/dynamic-icon';
import {Icons} from '@workspace/active-ui/components/composed/icons';

<DynamicIcon name={item.icon} className="size-4" aria-hidden />
<Icons.settings className="size-4" aria-hidden />
```

## Accessibility

Lucide icons are hidden from assistive technology by default. An icon that carries meaning on its
own, without text beside it, needs a name on the control around it.

## API

### DynamicIcon

**DynamicIcon**

| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `name` | `IconName` | yes | The name of a Lucide icon, such as `Settings` or `LayoutDashboard`. |

**DynamicIconProps**

```ts
interface DynamicIconProps extends icons.LucideProps {
  name: IconName;
}
```

**IconName**

```ts
type IconName = {
  [Name in keyof LucideExports]: LucideExports[Name] extends LucideIcon
    ? Name
    : never;
}[keyof LucideExports];
```

Every lucide-react export that is an icon component, aliases included
(`Trash2`, `AlertCircle`, `LanguagesIcon`). The package also exports values
that are not icons (`icons`, `createLucideIcon`, `LucideProvider`,
`useLucideContext`); rendering one of those by name would fail, so they are
not names.

### Icons

**Icons**: `{ arrowUpDown: LucideIcon; check: LucideIcon; chevronLeft: LucideIcon; chevronRight: LucideIcon; chevronsLeft: LucideIcon; chevronsRight: LucideIcon; code: LucideIcon; dot: LucideIcon; externalLink: LucideIcon; gallery: LucideIcon; layoutDashboard: LucideIcon; layoutGrid: LucideIcon; loader: LucideIcon; maximize: LucideIcon; minimize: LucideIcon; menu: LucideIcon; moon: LucideIcon; moveDown: LucideIcon; moveUp: LucideIcon; rotateCcw: LucideIcon; search: LucideIcon; settings: LucideIcon; sun: LucideIcon; x: LucideIcon; zoomIn: LucideIcon; zoomOut: LucideIcon; logo: (props: LucideProps) => JSX.Element; }`

A small set of Lucide icons under stable names, as the composed
components use them (`Icons.maximize`, `Icons.x`), and `logo`, a
placeholder mark from the original template to replace with your own.

**Icon**

```ts
import {type XIcon as LucideIcon} from 'lucide-react';
export {type LucideIcon as Icon};
```
