or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

custom-icons.mddocs/

0

# Custom Icon Creation

1

2

System for creating custom icon components from icon data, supporting Lucide Lab icons, custom SVG definitions, and creating new Lucide-style icon components.

3

4

## Capabilities

5

6

### Icon Component

7

8

The base `Icon` component renders SVG icons from icon node data, supporting custom icons and Lucide Lab integration.

9

10

```typescript { .api }

11

import type { SVGProps, ForwardRefExoticComponent, RefAttributes } from 'react';

12

13

type ElementAttributes = RefAttributes<SVGSVGElement> & Partial<SVGProps<SVGSVGElement>>;

14

15

/**

16

* Base icon component that renders SVG from IconNode data

17

* @param props - Icon props including iconNode and standard LucideProps

18

* @returns JSX.Element - Rendered SVG icon

19

*/

20

function Icon(props: IconComponentProps): JSX.Element;

21

22

interface IconComponentProps extends LucideProps {

23

/** Icon data structure defining SVG elements */

24

iconNode: IconNode;

25

/** Optional children to add to the SVG */

26

children?: React.ReactNode;

27

}

28

29

interface LucideProps extends ElementAttributes {

30

size?: string | number;

31

absoluteStrokeWidth?: boolean;

32

}

33

34

type IconNode = [elementName: SVGElementType, attrs: Record<string, string>][];

35

36

type SVGElementType =

37

| 'circle'

38

| 'ellipse'

39

| 'g'

40

| 'line'

41

| 'path'

42

| 'polygon'

43

| 'polyline'

44

| 'rect';

45

```

46

47

**Usage Examples:**

48

49

```typescript

50

import { Icon } from "lucide-react";

51

52

// Custom icon data

53

const customIconNode: IconNode = [

54

['path', { d: 'M12 2L2 7v10c0 5.55 3.84 10 9 10s9-4.45 9-10V7l-8-5z', key: 'custom1' }],

55

['path', { d: 'M12 8v8', key: 'custom2' }],

56

['path', { d: 'M8 12h8', key: 'custom3' }]

57

];

58

59

// Render custom icon

60

<Icon iconNode={customIconNode} size={32} color="blue" />

61

62

// With Lucide Lab icon

63

import { coconut } from '@lucide/lab';

64

<Icon iconNode={coconut} />

65

66

// With additional children

67

<Icon iconNode={customIconNode}>

68

<circle cx="12" cy="12" r="2" fill="red" />

69

</Icon>

70

```

71

72

### createLucideIcon Function

73

74

Factory function to create reusable icon components from icon data.

75

76

```typescript { .api }

77

/**

78

* Creates a reusable Lucide-style icon component from icon data

79

* @param iconName - Name for the icon (used for CSS classes and display name)

80

* @param iconNode - Icon data structure defining SVG elements

81

* @returns LucideIcon - Reusable React component with forwardRef

82

*/

83

function createLucideIcon(iconName: string, iconNode: IconNode): LucideIcon;

84

85

type LucideIcon = ForwardRefExoticComponent<

86

Omit<LucideProps, 'ref'> & RefAttributes<SVGSVGElement>

87

>;

88

```

89

90

**Usage Examples:**

91

92

```typescript

93

import { createLucideIcon } from "lucide-react";

94

95

// Define custom icon data

96

const heartIconNode: IconNode = [

97

['path', {

98

d: 'M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z',

99

key: 'heart1'

100

}]

101

];

102

103

// Create reusable component

104

const Heart = createLucideIcon('heart', heartIconNode);

105

106

// Use like any other Lucide icon

107

<Heart />

108

<Heart size={24} color="red" />

109

<Heart className="favorite-icon" />

110

```

111

112

### Icon Node Structure

113

114

The `IconNode` type defines how icon data is structured for rendering.

115

116

```typescript { .api }

117

/**

118

* Icon node structure representing SVG elements

119

* Each element is a tuple of [elementName, attributes]

120

*/

121

type IconNode = [elementName: SVGElementType, attrs: Record<string, string>][];

122

123

/**

124

* Supported SVG element types for icon definitions

125

*/

126

type SVGElementType =

127

| 'circle' // <circle cx="12" cy="12" r="5" />

128

| 'ellipse' // <ellipse cx="12" cy="12" rx="5" ry="3" />

129

| 'g' // <g transform="translate(2,2)">

130

| 'line' // <line x1="0" y1="0" x2="24" y2="24" />

131

| 'path' // <path d="M12 2L2 7v10..." />

132

| 'polygon' // <polygon points="12,2 22,7 22,17 12,22 2,17 2,7" />

133

| 'polyline' // <polyline points="12,2 22,7 22,17" />

134

| 'rect'; // <rect x="2" y="2" width="20" height="20" />

135

136

/**

137

* Element attributes are key-value pairs

138

* Common attributes: d, x, y, cx, cy, r, width, height, points, key

139

*/

140

type ElementAttributes = Record<string, string>;

141

```

142

143

**Usage Examples:**

144

145

```typescript

146

// Simple path icon

147

const simpleIcon: IconNode = [

148

['path', { d: 'M12 2v20', key: 'line1' }],

149

['path', { d: 'M2 12h20', key: 'line2' }]

150

];

151

152

// Complex icon with multiple elements

153

const complexIcon: IconNode = [

154

['rect', { x: '2', y: '2', width: '20', height: '20', rx: '5', key: 'bg' }],

155

['circle', { cx: '12', cy: '12', r: '3', key: 'center' }],

156

['path', { d: 'M12 1v6m0 10v6', key: 'vertical' }],

157

['path', { d: 'M1 12h6m10 0h6', key: 'horizontal' }]

158

];

159

160

// Group element for transformations

161

const groupIcon: IconNode = [

162

['g', { transform: 'translate(2,2) scale(0.8)', key: 'group' }],

163

['path', { d: 'M0 0h20v20H0z', key: 'square' }]

164

];

165

```

166

167

### Creating Icons from SVG

168

169

Convert existing SVG code to IconNode format for use with Lucide React.

170

171

```typescript { .api }

172

/**

173

* Converting SVG to IconNode:

174

* 1. Extract SVG elements (path, circle, etc.)

175

* 2. Convert to [elementName, attributes] tuples

176

* 3. Add unique 'key' attribute to each element

177

* 4. Use with Icon component or createLucideIcon

178

*/

179

```

180

181

**Usage Examples:**

182

183

```typescript

184

// Original SVG

185

/*

186

<svg viewBox="0 0 24 24">

187

<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/>

188

</svg>

189

*/

190

191

// Converted to IconNode

192

const starIcon: IconNode = [

193

['path', {

194

d: 'M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z',

195

key: 'star'

196

}]

197

];

198

199

// Create component

200

const Star = createLucideIcon('star', starIcon);

201

202

// Or use directly

203

<Icon iconNode={starIcon} />

204

```

205

206

### Icon Styling and Classes

207

208

Created icons automatically receive Lucide-style CSS classes and support all standard props.

209

210

```typescript { .api }

211

/**

212

* Created icons automatically receive CSS classes:

213

* - 'lucide' - Base class for all Lucide icons

214

* - 'lucide-{icon-name}' - Specific class for the icon

215

* - Additional classes from className prop

216

*/

217

```

218

219

**Usage Examples:**

220

221

```typescript

222

// Icon created with createLucideIcon gets automatic classes

223

const CustomIcon = createLucideIcon('my-custom-icon', iconNode);

224

225

// Results in classes: 'lucide lucide-my-custom-icon'

226

<CustomIcon />

227

228

// Additional classes

229

<CustomIcon className="my-extra-class" />

230

// Results in: 'lucide lucide-my-custom-icon my-extra-class'

231

232

// Direct Icon component also gets base class

233

<Icon iconNode={iconNode} className="custom-direct" />

234

// Results in: 'lucide custom-direct'

235

```

236

237

### Lucide Lab Integration

238

239

Use icons from Lucide Lab (experimental icons) with the Icon component.

240

241

```typescript { .api }

242

/**

243

* Lucide Lab provides experimental icons not in the main library

244

* Install: npm install @lucide/lab

245

* Icons are provided as IconNode data ready for use

246

*/

247

```

248

249

**Usage Examples:**

250

251

```typescript

252

import { Icon } from "lucide-react";

253

import { coconut, avocado, mango } from "@lucide/lab";

254

255

// Use lab icons directly

256

<Icon iconNode={coconut} />

257

<Icon iconNode={avocado} size={32} color="green" />

258

259

// Create reusable components from lab icons

260

const Coconut = createLucideIcon('coconut', coconut);

261

const Avocado = createLucideIcon('avocado', avocado);

262

263

// Use like standard Lucide icons

264

<Coconut />

265

<Avocado size={24} />

266

```

267

268

### Default Attributes

269

270

Custom icons inherit the same default SVG attributes as built-in icons.

271

272

```typescript { .api }

273

/**

274

* Default attributes applied to all custom icons:

275

* - xmlns: "http://www.w3.org/2000/svg"

276

* - width: 24, height: 24

277

* - viewBox: "0 0 24 24"

278

* - fill: "none"

279

* - stroke: "currentColor"

280

* - strokeWidth: 2

281

* - strokeLinecap: "round"

282

* - strokeLinejoin: "round"

283

*/

284

```

285

286

### Accessibility

287

288

Custom icons support the same accessibility features as built-in icons.

289

290

```typescript { .api }

291

/**

292

* Accessibility features:

293

* - Automatic aria-hidden="true" for decorative icons

294

* - Support for aria-label and role attributes

295

* - Proper focus management with ref support

296

*/

297

```

298

299

**Usage Examples:**

300

301

```typescript

302

// Decorative icon (automatic aria-hidden)

303

<Icon iconNode={customIcon} />

304

305

// Semantic icon with label

306

<Icon

307

iconNode={customIcon}

308

role="img"

309

aria-label="Custom action"

310

/>

311

312

// Interactive icon

313

<button>

314

<Icon iconNode={customIcon} aria-hidden="true" />

315

<span className="sr-only">Perform action</span>

316

</button>

317

```