or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

custom-icons.mddynamic-icons.mdindex.mdstatic-icons.md

dynamic-icons.mddocs/

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

```