0
# Dynamic Icon Loading
1
2
Runtime icon loading system for displaying icons based on string names. The dynamic loading system is useful for CMS-driven applications or when icon selection is determined at runtime, but comes with the trade-off of including all icons in the bundle.
3
4
## Capabilities
5
6
### DynamicIcon Component
7
8
The `DynamicIcon` component loads icons dynamically by name at runtime.
9
10
```typescript { .api }
11
import type { SVGProps, RefAttributes } from 'react';
12
13
type ElementAttributes = RefAttributes<SVGSVGElement> & Partial<SVGProps<SVGSVGElement>>;
14
15
/**
16
* Dynamic icon component that loads icons by name at runtime
17
* @param props - DynamicIcon props including name and standard LucideProps
18
* @returns JSX.Element or null/fallback
19
*/
20
function DynamicIcon(props: DynamicIconProps): JSX.Element;
21
22
interface DynamicIconProps extends LucideProps {
23
/** Name of the icon to load */
24
name: IconName;
25
/** Fallback component to render while loading or on error */
26
fallback?: () => JSX.Element | null;
27
}
28
29
interface LucideProps extends ElementAttributes {
30
size?: string | number;
31
absoluteStrokeWidth?: boolean;
32
}
33
```
34
35
**Usage Examples:**
36
37
```typescript
38
import { DynamicIcon } from "lucide-react/dynamic";
39
40
// Basic usage
41
<DynamicIcon name="camera" />
42
43
// With props
44
<DynamicIcon
45
name="grid"
46
size={32}
47
color="blue"
48
strokeWidth={3}
49
/>
50
51
// With fallback
52
<DynamicIcon
53
name="unknown-icon"
54
fallback={() => <div>Loading...</div>}
55
/>
56
57
// From variable
58
const iconName = "chevron-right";
59
<DynamicIcon name={iconName} />
60
```
61
62
### Icon Names
63
64
The `IconName` type and `iconNames` array provide access to all available icon names.
65
66
```typescript { .api }
67
/**
68
* Type representing all valid icon names
69
* Generated from the available icons in the dynamic imports
70
*/
71
type IconName = keyof typeof dynamicIconImports;
72
73
/**
74
* Array of all available icon names
75
* Useful for iteration or validation
76
*/
77
const iconNames: Array<IconName>;
78
```
79
80
**Usage Examples:**
81
82
```typescript
83
import { iconNames, IconName } from "lucide-react/dynamic";
84
85
// Validate icon name
86
function isValidIconName(name: string): name is IconName {
87
return iconNames.includes(name as IconName);
88
}
89
90
// Iterate over all icons
91
iconNames.forEach(name => {
92
console.log(`Icon: ${name}`);
93
});
94
95
// Generate icon picker
96
const IconPicker = () => (
97
<div>
98
{iconNames.map(name => (
99
<DynamicIcon key={name} name={name} size={24} />
100
))}
101
</div>
102
);
103
104
// Type-safe icon name handling
105
const handleIconSelect = (name: IconName) => {
106
setSelectedIcon(name);
107
};
108
```
109
110
### Dynamic Icon Imports
111
112
The underlying dynamic import system maps icon names to import functions.
113
114
```typescript { .api }
115
/**
116
* Dynamic import mapping object (internal)
117
* Maps icon names to functions that return icon modules
118
*/
119
const dynamicIconImports: Record<string, () => Promise<DynamicIconModule>>;
120
121
/**
122
* Structure of dynamically imported icon modules
123
*/
124
interface DynamicIconModule {
125
default: LucideIcon;
126
__iconNode: IconNode;
127
}
128
129
type IconNode = [elementName: SVGElementType, attrs: Record<string, string>][];
130
```
131
132
### Loading Behavior
133
134
The `DynamicIcon` component handles asynchronous loading with React hooks.
135
136
```typescript { .api }
137
/**
138
* DynamicIcon loading states:
139
* 1. Initial render: null or fallback
140
* 2. Loading: fallback component (if provided)
141
* 3. Loaded: rendered icon
142
* 4. Error: fallback component or null
143
*/
144
```
145
146
**Usage Examples:**
147
148
```typescript
149
import { DynamicIcon } from "lucide-react/dynamic";
150
151
// Loading indicator
152
const LoadingSpinner = () => <div className="spinner">Loading...</div>;
153
154
// Error fallback
155
const ErrorIcon = () => <div className="error">❌</div>;
156
157
// Comprehensive fallback handling
158
<DynamicIcon
159
name={userSelectedIcon}
160
fallback={() => (
161
userSelectedIcon ? <LoadingSpinner /> : <ErrorIcon />
162
)}
163
/>
164
165
// Conditional rendering
166
const MyIcon = ({ iconName }: { iconName: string }) => {
167
if (!iconNames.includes(iconName as IconName)) {
168
return <div>Invalid icon</div>;
169
}
170
171
return <DynamicIcon name={iconName as IconName} />;
172
};
173
```
174
175
### Performance Considerations
176
177
Dynamic icons have different performance characteristics compared to static imports.
178
179
```typescript { .api }
180
/**
181
* Performance implications:
182
* - All icons are included in the bundle (no tree-shaking)
183
* - Icons are loaded asynchronously on first use
184
* - Subsequent uses of the same icon are cached
185
* - Bundle size is larger but individual icons load faster
186
*/
187
```
188
189
**Best Practices:**
190
191
```typescript
192
// ❌ Not recommended for static icon usage
193
<DynamicIcon name="camera" /> // Known at build time
194
195
// ✅ Recommended for static usage
196
import { Camera } from "lucide-react";
197
<Camera />
198
199
// ✅ Good use case for dynamic icons
200
const IconDisplay = ({ iconName }: { iconName: string }) => (
201
<DynamicIcon name={iconName as IconName} />
202
);
203
204
// ✅ CMS or user-driven icon selection
205
const UserIcon = ({ user }: { user: User }) => (
206
<DynamicIcon name={user.preferredIcon} />
207
);
208
```
209
210
### Error Handling
211
212
Handle cases where icon names are invalid or loading fails.
213
214
```typescript { .api }
215
/**
216
* Error scenarios:
217
* - Invalid icon name (not in iconNames)
218
* - Import failure (network issues, missing files)
219
* - Module loading errors
220
*/
221
```
222
223
**Usage Examples:**
224
225
```typescript
226
import { DynamicIcon, iconNames, IconName } from "lucide-react/dynamic";
227
228
// Safe icon component with validation
229
const SafeIcon = ({ name, ...props }: { name: string } & LucideProps) => {
230
if (!iconNames.includes(name as IconName)) {
231
console.warn(`Invalid icon name: ${name}`);
232
return <div>Invalid Icon</div>;
233
}
234
235
return (
236
<DynamicIcon
237
name={name as IconName}
238
fallback={() => <div>Loading...</div>}
239
{...props}
240
/>
241
);
242
};
243
244
// With TypeScript validation
245
const validateAndRenderIcon = (iconName: unknown) => {
246
if (typeof iconName === 'string' && iconNames.includes(iconName as IconName)) {
247
return <DynamicIcon name={iconName as IconName} />;
248
}
249
return <div>Invalid icon name</div>;
250
};
251
```
252
253
### Client-Side Directive
254
255
Dynamic icons include a 'use client' directive for Next.js app router compatibility.
256
257
```typescript { .api }
258
/**
259
* Dynamic icons are marked with 'use client' for Next.js compatibility
260
* This ensures they work properly in server-side rendering scenarios
261
*/
262
```