0
# Icons
1
2
Comprehensive icon system supporting multiple icon sets including Material Design Icons, Font Awesome, and custom icon implementations with flexible configuration and theming support.
3
4
## Capabilities
5
6
### IconOptions Interface
7
8
Core configuration interface for setting up the icon system during Vuetify initialization.
9
10
```typescript { .api }
11
/**
12
* Icon system configuration options
13
*/
14
interface IconOptions {
15
/** Default icon set to use */
16
defaultSet?: string;
17
/** Icon alias mappings */
18
aliases?: IconAliases;
19
/** Available icon sets */
20
sets?: Record<string, IconSet>;
21
}
22
23
interface IconAliases {
24
/** Collapse icon */
25
collapse?: IconValue;
26
/** Complete icon */
27
complete?: IconValue;
28
/** Cancel icon */
29
cancel?: IconValue;
30
/** Close icon */
31
close?: IconValue;
32
/** Delete icon */
33
delete?: IconValue;
34
/** Clear icon */
35
clear?: IconValue;
36
/** Success icon */
37
success?: IconValue;
38
/** Info icon */
39
info?: IconValue;
40
/** Warning icon */
41
warning?: IconValue;
42
/** Error icon */
43
error?: IconValue;
44
/** Prev icon */
45
prev?: IconValue;
46
/** Next icon */
47
next?: IconValue;
48
/** Check icon */
49
checkboxOn?: IconValue;
50
/** Unchecked icon */
51
checkboxOff?: IconValue;
52
/** Indeterminate icon */
53
checkboxIndeterminate?: IconValue;
54
/** Delimiter icon */
55
delimiter?: IconValue;
56
/** Sort icon */
57
sort?: IconValue;
58
/** Expand icon */
59
expand?: IconValue;
60
/** Menu icon */
61
menu?: IconValue;
62
/** Subgroup icon */
63
subgroup?: IconValue;
64
/** Dropdown icon */
65
dropdown?: IconValue;
66
/** Radio on icon */
67
radioOn?: IconValue;
68
/** Radio off icon */
69
radioOff?: IconValue;
70
/** Edit icon */
71
edit?: IconValue;
72
/** Rating empty icon */
73
ratingEmpty?: IconValue;
74
/** Rating full icon */
75
ratingFull?: IconValue;
76
/** Rating half icon */
77
ratingHalf?: IconValue;
78
/** Loading icon */
79
loading?: IconValue;
80
/** First page icon */
81
first?: IconValue;
82
/** Last page icon */
83
last?: IconValue;
84
/** Unfold icon */
85
unfold?: IconValue;
86
/** File icon */
87
file?: IconValue;
88
/** Plus icon */
89
plus?: IconValue;
90
/** Minus icon */
91
minus?: IconValue;
92
/** Calendar icon */
93
calendar?: IconValue;
94
}
95
96
interface IconSet {
97
/** Icon component to render */
98
component: Component;
99
/** Default props for icon component */
100
props?: IconProps;
101
}
102
103
interface IconProps {
104
/** Icon color */
105
color?: string;
106
/** Icon size */
107
size?: string | number;
108
/** Icon tag */
109
tag?: string;
110
/** Icon theme */
111
theme?: string;
112
}
113
114
type IconValue = string | [string, number] | ComponentPublicInstance;
115
```
116
117
**Usage Examples:**
118
119
```javascript
120
// vuetify.js configuration
121
import { createVuetify } from 'vuetify';
122
import { aliases, mdi } from 'vuetify/iconsets/mdi';
123
import { fa } from 'vuetify/iconsets/fa';
124
import '@mdi/font/css/materialdesignicons.css';
125
import '@fortawesome/fontawesome-free/css/all.css';
126
127
const vuetify = createVuetify({
128
icons: {
129
defaultSet: 'mdi',
130
aliases,
131
sets: {
132
mdi,
133
fa,
134
custom: {
135
component: CustomIconComponent,
136
props: {
137
tag: 'i',
138
size: 'default'
139
}
140
}
141
}
142
}
143
});
144
```
145
146
### VIcon Component
147
148
Core icon display component with support for multiple icon sets and customization options.
149
150
```typescript { .api }
151
/**
152
* Icon display component
153
*/
154
const VIcon: Component;
155
156
interface IconComponentProps {
157
/** Icon identifier */
158
icon?: IconValue;
159
/** Icon color */
160
color?: string;
161
/** Icon size */
162
size?: string | number | 'x-small' | 'small' | 'default' | 'large' | 'x-large';
163
/** Icon density */
164
density?: 'default' | 'comfortable' | 'compact';
165
/** Icon tag element */
166
tag?: string;
167
/** Icon theme */
168
theme?: string;
169
/** Start icon (for text direction) */
170
start?: boolean;
171
/** End icon (for text direction) */
172
end?: boolean;
173
/** Disabled state */
174
disabled?: boolean;
175
}
176
177
// Events
178
interface IconEvents {
179
'click': (event: MouseEvent) => void;
180
}
181
```
182
183
**Usage Examples:**
184
185
```vue
186
<template>
187
<div>
188
<!-- Basic icons -->
189
<v-icon>mdi-home</v-icon>
190
<v-icon icon="mdi-account" />
191
<v-icon>$vuetify.icons.menu</v-icon>
192
193
<!-- Sized icons -->
194
<v-icon size="x-small">mdi-heart</v-icon>
195
<v-icon size="small">mdi-heart</v-icon>
196
<v-icon size="default">mdi-heart</v-icon>
197
<v-icon size="large">mdi-heart</v-icon>
198
<v-icon size="x-large">mdi-heart</v-icon>
199
<v-icon size="64">mdi-heart</v-icon>
200
201
<!-- Colored icons -->
202
<v-icon color="primary">mdi-home</v-icon>
203
<v-icon color="red">mdi-heart</v-icon>
204
<v-icon color="#FF5722">mdi-favorite</v-icon>
205
206
<!-- Clickable icons -->
207
<v-icon @click="handleClick">mdi-menu</v-icon>
208
209
<!-- Icons in buttons -->
210
<v-btn icon>
211
<v-icon>mdi-heart</v-icon>
212
</v-btn>
213
214
<v-btn prepend-icon="mdi-account" append-icon="mdi-chevron-down">
215
User Menu
216
</v-btn>
217
218
<!-- Font Awesome icons -->
219
<v-icon>fas fa-home</v-icon>
220
<v-icon>fab fa-vuejs</v-icon>
221
222
<!-- Custom icon component -->
223
<v-icon icon="custom:my-icon" />
224
225
<!-- Dynamic icons -->
226
<v-icon :icon="currentIcon" :color="iconColor" />
227
</div>
228
</template>
229
230
<script setup>
231
const currentIcon = ref('mdi-home');
232
const iconColor = ref('primary');
233
234
const handleClick = () => {
235
console.log('Icon clicked');
236
};
237
238
const cycleIcon = () => {
239
const icons = ['mdi-home', 'mdi-account', 'mdi-settings', 'mdi-heart'];
240
const currentIndex = icons.indexOf(currentIcon.value);
241
currentIcon.value = icons[(currentIndex + 1) % icons.length];
242
};
243
</script>
244
```
245
246
### Icon Sets
247
248
Pre-configured icon sets for different icon libraries with optimized loading and rendering.
249
250
```typescript { .api }
251
/**
252
* Material Design Icons (MDI) icon set
253
*/
254
interface MdiIconSet extends IconSet {
255
component: Component;
256
props: {
257
tag: 'i';
258
class: 'mdi';
259
};
260
}
261
262
/**
263
* Font Awesome icon set
264
*/
265
interface FontAwesomeIconSet extends IconSet {
266
component: Component;
267
props: {
268
tag: 'i';
269
class: string;
270
};
271
}
272
273
/**
274
* Material Design (Google) icon set
275
*/
276
interface MaterialIconSet extends IconSet {
277
component: Component;
278
props: {
279
tag: 'i';
280
class: 'material-icons';
281
};
282
}
283
284
/**
285
* SVG icon set for custom implementations
286
*/
287
interface SvgIconSet extends IconSet {
288
component: Component;
289
props: {
290
tag: 'svg';
291
viewBox: '0 0 24 24';
292
};
293
}
294
295
// Available icon sets
296
const mdi: MdiIconSet;
297
const fa: FontAwesomeIconSet;
298
const fa4: FontAwesomeIconSet; // Font Awesome 4 compatibility
299
const faSvg: SvgIconSet; // Font Awesome SVG
300
const md: MaterialIconSet; // Google Material Design
301
const mdiSvg: SvgIconSet; // MDI SVG format
302
```
303
304
**Usage Examples:**
305
306
```vue
307
<template>
308
<div>
309
<!-- Material Design Icons -->
310
<v-card class="mb-4">
311
<v-card-title>
312
<v-icon>mdi-palette</v-icon>
313
Material Design Icons
314
</v-card-title>
315
<v-card-text>
316
<div class="icon-grid">
317
<div v-for="icon in mdiIcons" :key="icon.name" class="icon-item">
318
<v-icon :size="32">{{ icon.name }}</v-icon>
319
<span class="icon-label">{{ icon.label }}</span>
320
</div>
321
</div>
322
</v-card-text>
323
</v-card>
324
325
<!-- Font Awesome Icons -->
326
<v-card class="mb-4">
327
<v-card-title>
328
<v-icon>fab fa-font-awesome</v-icon>
329
Font Awesome Icons
330
</v-card-title>
331
<v-card-text>
332
<div class="icon-grid">
333
<div v-for="icon in faIcons" :key="icon.name" class="icon-item">
334
<v-icon :size="32">{{ icon.name }}</v-icon>
335
<span class="icon-label">{{ icon.label }}</span>
336
</div>
337
</div>
338
</v-card-text>
339
</v-card>
340
341
<!-- Google Material Icons -->
342
<v-card class="mb-4">
343
<v-card-title>
344
<v-icon>md:home</v-icon>
345
Google Material Icons
346
</v-card-title>
347
<v-card-text>
348
<div class="icon-grid">
349
<div v-for="icon in materialIcons" :key="icon.name" class="icon-item">
350
<v-icon :size="32">{{ icon.name }}</v-icon>
351
<span class="icon-label">{{ icon.label }}</span>
352
</div>
353
</div>
354
</v-card-text>
355
</v-card>
356
357
<!-- SVG Icons -->
358
<v-card class="mb-4">
359
<v-card-title>
360
<CustomSvgIcon />
361
Custom SVG Icons
362
</v-card-title>
363
<v-card-text>
364
<div class="icon-grid">
365
<div v-for="icon in svgIcons" :key="icon.name" class="icon-item">
366
<component :is="icon.component" :size="32" />
367
<span class="icon-label">{{ icon.label }}</span>
368
</div>
369
</div>
370
</v-card-text>
371
</v-card>
372
373
<!-- Icon set comparison -->
374
<v-card>
375
<v-card-title>Icon Set Comparison</v-card-title>
376
<v-card-text>
377
<v-simple-table>
378
<template #default>
379
<thead>
380
<tr>
381
<th>Icon Set</th>
382
<th>Format</th>
383
<th>Size</th>
384
<th>Icons Count</th>
385
<th>Example</th>
386
</tr>
387
</thead>
388
<tbody>
389
<tr>
390
<td>Material Design Icons</td>
391
<td>Font/SVG</td>
392
<td>~500KB</td>
393
<td>7000+</td>
394
<td><v-icon>mdi-vuetify</v-icon></td>
395
</tr>
396
<tr>
397
<td>Font Awesome</td>
398
<td>Font/SVG</td>
399
<td>~400KB</td>
400
<td>1600+</td>
401
<td><v-icon>fas fa-star</v-icon></td>
402
</tr>
403
<tr>
404
<td>Google Material</td>
405
<td>Font</td>
406
<td>~50KB</td>
407
<td>1000+</td>
408
<td><v-icon>md:star</v-icon></td>
409
</tr>
410
<tr>
411
<td>Custom SVG</td>
412
<td>SVG</td>
413
<td>Varies</td>
414
<td>Custom</td>
415
<td><CustomSvgIcon size="24" /></td>
416
</tr>
417
</tbody>
418
</template>
419
</v-simple-table>
420
</v-card-text>
421
</v-card>
422
</div>
423
</template>
424
425
<script setup>
426
const mdiIcons = [
427
{ name: 'mdi-home', label: 'Home' },
428
{ name: 'mdi-account', label: 'Account' },
429
{ name: 'mdi-settings', label: 'Settings' },
430
{ name: 'mdi-heart', label: 'Heart' },
431
{ name: 'mdi-star', label: 'Star' },
432
{ name: 'mdi-check', label: 'Check' },
433
{ name: 'mdi-close', label: 'Close' },
434
{ name: 'mdi-menu', label: 'Menu' },
435
{ name: 'mdi-search', label: 'Search' },
436
{ name: 'mdi-shopping', label: 'Shopping' }
437
];
438
439
const faIcons = [
440
{ name: 'fas fa-home', label: 'Home' },
441
{ name: 'fas fa-user', label: 'User' },
442
{ name: 'fas fa-cog', label: 'Settings' },
443
{ name: 'fas fa-heart', label: 'Heart' },
444
{ name: 'fas fa-star', label: 'Star' },
445
{ name: 'fas fa-check', label: 'Check' },
446
{ name: 'fas fa-times', label: 'Close' },
447
{ name: 'fas fa-bars', label: 'Menu' },
448
{ name: 'fas fa-search', label: 'Search' },
449
{ name: 'fas fa-shopping-cart', label: 'Shopping' }
450
];
451
452
const materialIcons = [
453
{ name: 'md:home', label: 'Home' },
454
{ name: 'md:person', label: 'Person' },
455
{ name: 'md:settings', label: 'Settings' },
456
{ name: 'md:favorite', label: 'Favorite' },
457
{ name: 'md:star', label: 'Star' },
458
{ name: 'md:check', label: 'Check' },
459
{ name: 'md:close', label: 'Close' },
460
{ name: 'md:menu', label: 'Menu' },
461
{ name: 'md:search', label: 'Search' },
462
{ name: 'md:shopping_cart', label: 'Shopping' }
463
];
464
465
const svgIcons = [
466
{ name: 'custom-icon-1', label: 'Custom 1', component: CustomIcon1 },
467
{ name: 'custom-icon-2', label: 'Custom 2', component: CustomIcon2 },
468
];
469
</script>
470
471
<style>
472
.icon-grid {
473
display: grid;
474
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
475
gap: 16px;
476
}
477
478
.icon-item {
479
display: flex;
480
flex-direction: column;
481
align-items: center;
482
gap: 8px;
483
padding: 16px;
484
border-radius: 8px;
485
background: rgba(0,0,0,0.02);
486
transition: background-color 0.2s;
487
}
488
489
.icon-item:hover {
490
background: rgba(0,0,0,0.05);
491
}
492
493
.icon-label {
494
font-size: 0.75rem;
495
text-align: center;
496
color: rgba(0,0,0,0.6);
497
}
498
</style>
499
```
500
501
### Custom Icon Implementation
502
503
Creating and registering custom icon sets and components for specialized use cases.
504
505
```typescript { .api }
506
/**
507
* Custom icon component interface
508
*/
509
interface CustomIconComponent {
510
/** Icon name or identifier */
511
name?: string;
512
/** Icon size */
513
size?: string | number;
514
/** Icon color */
515
color?: string;
516
/** Additional CSS classes */
517
class?: string | string[];
518
/** Inline styles */
519
style?: Record<string, any>;
520
/** Accessibility label */
521
'aria-label'?: string;
522
/** Icon title for tooltips */
523
title?: string;
524
}
525
526
/**
527
* SVG icon definition
528
*/
529
interface SvgIconDefinition {
530
/** SVG path data */
531
path: string;
532
/** ViewBox dimensions */
533
viewBox?: string;
534
/** Icon width */
535
width?: number;
536
/** Icon height */
537
height?: number;
538
}
539
540
/**
541
* Icon registry for custom icons
542
*/
543
interface IconRegistry {
544
/** Register new icon */
545
register: (name: string, definition: SvgIconDefinition | Component) => void;
546
/** Unregister icon */
547
unregister: (name: string) => void;
548
/** Get icon definition */
549
get: (name: string) => SvgIconDefinition | Component | undefined;
550
/** List all registered icons */
551
list: () => string[];
552
}
553
```
554
555
**Usage Examples:**
556
557
```vue
558
<template>
559
<div>
560
<!-- Custom SVG icon component -->
561
<svg-icon name="custom-logo" :size="48" color="primary" />
562
563
<!-- Custom icon with animation -->
564
<animated-icon name="loading-spinner" :size="32" />
565
566
<!-- Icon with custom styling -->
567
<custom-icon
568
name="brand-icon"
569
:size="40"
570
:style="{ filter: 'drop-shadow(2px 2px 4px rgba(0,0,0,0.3))' }"
571
/>
572
573
<!-- Custom icon gallery -->
574
<v-card>
575
<v-card-title>Custom Icons</v-card-title>
576
<v-card-text>
577
<div class="custom-icon-grid">
578
<div
579
v-for="icon in customIcons"
580
:key="icon.name"
581
class="custom-icon-item"
582
>
583
<component
584
:is="icon.component"
585
:name="icon.name"
586
:size="48"
587
:color="icon.color"
588
/>
589
<span>{{ icon.label }}</span>
590
</div>
591
</div>
592
</v-card-text>
593
</v-card>
594
</div>
595
</template>
596
597
<script setup>
598
// Custom SVG Icon Component
599
const SvgIcon = defineComponent({
600
props: {
601
name: String,
602
size: {
603
type: [String, Number],
604
default: 24
605
},
606
color: {
607
type: String,
608
default: 'currentColor'
609
}
610
},
611
setup(props) {
612
const iconDefinitions = {
613
'custom-logo': {
614
path: 'M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5',
615
viewBox: '0 0 24 24'
616
},
617
'brand-icon': {
618
path: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z',
619
viewBox: '0 0 24 24'
620
}
621
};
622
623
const iconDef = computed(() => iconDefinitions[props.name]);
624
625
return () => {
626
if (!iconDef.value) return null;
627
628
return h('svg', {
629
width: props.size,
630
height: props.size,
631
viewBox: iconDef.value.viewBox,
632
fill: props.color,
633
class: 'custom-svg-icon'
634
}, [
635
h('path', { d: iconDef.value.path })
636
]);
637
};
638
}
639
});
640
641
// Animated Icon Component
642
const AnimatedIcon = defineComponent({
643
props: {
644
name: String,
645
size: {
646
type: [String, Number],
647
default: 24
648
}
649
},
650
setup(props) {
651
const animations = {
652
'loading-spinner': {
653
path: 'M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z',
654
animation: 'spin 1s linear infinite'
655
},
656
'pulse-heart': {
657
path: 'M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5 2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z',
658
animation: 'pulse 2s ease-in-out infinite'
659
}
660
};
661
662
const iconDef = computed(() => animations[props.name]);
663
664
return () => {
665
if (!iconDef.value) return null;
666
667
return h('svg', {
668
width: props.size,
669
height: props.size,
670
viewBox: '0 0 24 24',
671
fill: 'currentColor',
672
style: {
673
animation: iconDef.value.animation
674
},
675
class: 'animated-icon'
676
}, [
677
h('path', { d: iconDef.value.path })
678
]);
679
};
680
}
681
});
682
683
const customIcons = [
684
{
685
name: 'custom-logo',
686
label: 'Custom Logo',
687
component: SvgIcon,
688
color: 'primary'
689
},
690
{
691
name: 'brand-icon',
692
label: 'Brand Icon',
693
component: SvgIcon,
694
color: 'success'
695
},
696
{
697
name: 'loading-spinner',
698
label: 'Loading',
699
component: AnimatedIcon,
700
color: 'info'
701
},
702
{
703
name: 'pulse-heart',
704
label: 'Pulse Heart',
705
component: AnimatedIcon,
706
color: 'error'
707
}
708
];
709
</script>
710
711
<style>
712
@keyframes spin {
713
from { transform: rotate(0deg); }
714
to { transform: rotate(360deg); }
715
}
716
717
@keyframes pulse {
718
0%, 100% { transform: scale(1); }
719
50% { transform: scale(1.2); }
720
}
721
722
.custom-icon-grid {
723
display: grid;
724
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
725
gap: 20px;
726
}
727
728
.custom-icon-item {
729
display: flex;
730
flex-direction: column;
731
align-items: center;
732
gap: 12px;
733
padding: 20px;
734
border-radius: 12px;
735
background: rgba(0,0,0,0.02);
736
transition: all 0.3s ease;
737
}
738
739
.custom-icon-item:hover {
740
background: rgba(0,0,0,0.05);
741
transform: translateY(-2px);
742
}
743
744
.animated-icon {
745
transform-origin: center;
746
}
747
748
.custom-svg-icon {
749
transition: all 0.2s ease;
750
}
751
</style>
752
```
753
754
### Icon Loading and Performance
755
756
Optimization strategies for icon loading, bundle size management, and performance considerations.
757
758
```typescript { .api }
759
/**
760
* Icon loading strategies
761
*/
762
interface IconLoadingOptions {
763
/** Lazy load icons */
764
lazy?: boolean;
765
/** Preload critical icons */
766
preload?: string[];
767
/** Icon bundle splitting */
768
bundles?: IconBundle[];
769
/** Cache configuration */
770
cache?: IconCacheOptions;
771
}
772
773
interface IconBundle {
774
/** Bundle name */
775
name: string;
776
/** Icons in bundle */
777
icons: string[];
778
/** Loading strategy */
779
strategy: 'eager' | 'lazy' | 'preload';
780
}
781
782
interface IconCacheOptions {
783
/** Cache duration in milliseconds */
784
duration?: number;
785
/** Maximum cache size */
786
maxSize?: number;
787
/** Storage type */
788
storage?: 'memory' | 'localStorage' | 'sessionStorage';
789
}
790
791
/**
792
* Tree shaking support for icons
793
*/
794
interface TreeShakableIconSet {
795
/** Only include used icons */
796
treeShake: boolean;
797
/** Icon usage tracking */
798
usage?: IconUsageTracker;
799
}
800
801
interface IconUsageTracker {
802
/** Track icon usage */
803
track: (iconName: string) => void;
804
/** Get usage statistics */
805
getStats: () => IconUsageStats;
806
/** Reset tracking data */
807
reset: () => void;
808
}
809
810
interface IconUsageStats {
811
/** Total icons used */
812
totalUsed: number;
813
/** Most used icons */
814
mostUsed: Array<{ name: string; count: number }>;
815
/** Unused icons */
816
unused: string[];
817
}
818
```
819
820
**Usage Examples:**
821
822
```javascript
823
// Optimized icon configuration
824
import { createVuetify } from 'vuetify';
825
826
// Tree-shaken icon imports (only imports used icons)
827
import {
828
mdiHome,
829
mdiAccount,
830
mdiSettings,
831
mdiHeart,
832
mdiStar
833
} from '@mdi/js';
834
835
// Custom icon set with tree shaking
836
const optimizedMdi = {
837
component: (props) => h(SvgIcon, props),
838
props: {
839
tag: 'svg'
840
},
841
// Define only the icons you need
842
icons: {
843
home: mdiHome,
844
account: mdiAccount,
845
settings: mdiSettings,
846
heart: mdiHeart,
847
star: mdiStar
848
}
849
};
850
851
const vuetify = createVuetify({
852
icons: {
853
defaultSet: 'optimizedMdi',
854
sets: {
855
optimizedMdi
856
}
857
}
858
});
859
860
// Lazy loading icon strategy
861
const lazyIconLoader = {
862
async loadIcon(iconName) {
863
// Dynamic import for unused icons
864
const iconModule = await import(`@mdi/js/${iconName}`);
865
return iconModule[iconName];
866
},
867
868
cache: new Map(),
869
870
async getIcon(iconName) {
871
if (this.cache.has(iconName)) {
872
return this.cache.get(iconName);
873
}
874
875
const iconData = await this.loadIcon(iconName);
876
this.cache.set(iconName, iconData);
877
return iconData;
878
}
879
};
880
881
// Performance monitoring
882
const iconPerformanceMonitor = {
883
startTimes: new Map(),
884
885
startLoad(iconName) {
886
this.startTimes.set(iconName, performance.now());
887
},
888
889
endLoad(iconName) {
890
const startTime = this.startTimes.get(iconName);
891
if (startTime) {
892
const loadTime = performance.now() - startTime;
893
console.log(`Icon ${iconName} loaded in ${loadTime.toFixed(2)}ms`);
894
this.startTimes.delete(iconName);
895
}
896
}
897
};
898
```
899
900
## Types
901
902
```typescript { .api }
903
// Core icon types
904
type IconIdentifier = string;
905
type IconSize = 'x-small' | 'small' | 'default' | 'large' | 'x-large' | number | string;
906
type IconColor = string;
907
908
// Icon value types
909
type IconValue =
910
| string // Icon name: 'mdi-home'
911
| [string, number] // Icon with rotation: ['mdi-home', 90]
912
| ComponentPublicInstance; // Custom component
913
914
// Icon set types
915
type IconSetName = 'mdi' | 'fa' | 'fa4' | 'fa-svg' | 'md' | 'mdi-svg' | string;
916
917
// Icon format types
918
type IconFormat = 'font' | 'svg' | 'component';
919
920
// Icon component types
921
interface IconComponentType {
922
name: string;
923
props: Record<string, any>;
924
render: () => VNode;
925
}
926
927
// Accessibility types
928
interface IconAccessibility {
929
label?: string;
930
describedBy?: string;
931
hidden?: boolean;
932
role?: string;
933
}
934
935
// Icon state types
936
type IconState = 'loading' | 'loaded' | 'error' | 'cached';
937
938
// Icon metrics
939
interface IconMetrics {
940
loadTime: number;
941
renderTime: number;
942
cacheHit: boolean;
943
bundleSize: number;
944
}
945
946
// Icon theme integration
947
interface IconTheme {
948
colors: Record<string, string>;
949
sizes: Record<string, number>;
950
variants: Record<string, IconProps>;
951
}
952
```