CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vuetify

Vue Material Component Framework implementing Google's Material Design specification with comprehensive UI components, theming system, and accessibility features.

Pending
Overview
Eval results
Files

icons.mddocs/

Icons

Comprehensive icon system supporting multiple icon sets including Material Design Icons, Font Awesome, and custom icon implementations with flexible configuration and theming support.

Capabilities

IconOptions Interface

Core configuration interface for setting up the icon system during Vuetify initialization.

/**
 * Icon system configuration options
 */
interface IconOptions {
  /** Default icon set to use */
  defaultSet?: string;
  /** Icon alias mappings */
  aliases?: IconAliases;
  /** Available icon sets */
  sets?: Record<string, IconSet>;
}

interface IconAliases {
  /** Collapse icon */
  collapse?: IconValue;
  /** Complete icon */
  complete?: IconValue;
  /** Cancel icon */
  cancel?: IconValue;
  /** Close icon */
  close?: IconValue;
  /** Delete icon */
  delete?: IconValue;
  /** Clear icon */
  clear?: IconValue;
  /** Success icon */
  success?: IconValue;
  /** Info icon */
  info?: IconValue;
  /** Warning icon */
  warning?: IconValue;
  /** Error icon */
  error?: IconValue;
  /** Prev icon */
  prev?: IconValue;
  /** Next icon */
  next?: IconValue;
  /** Check icon */
  checkboxOn?: IconValue;
  /** Unchecked icon */
  checkboxOff?: IconValue;
  /** Indeterminate icon */
  checkboxIndeterminate?: IconValue;
  /** Delimiter icon */
  delimiter?: IconValue;
  /** Sort icon */
  sort?: IconValue;
  /** Expand icon */
  expand?: IconValue;
  /** Menu icon */
  menu?: IconValue;
  /** Subgroup icon */
  subgroup?: IconValue;
  /** Dropdown icon */
  dropdown?: IconValue;
  /** Radio on icon */
  radioOn?: IconValue;
  /** Radio off icon */
  radioOff?: IconValue;
  /** Edit icon */
  edit?: IconValue;
  /** Rating empty icon */
  ratingEmpty?: IconValue;
  /** Rating full icon */
  ratingFull?: IconValue;
  /** Rating half icon */
  ratingHalf?: IconValue;
  /** Loading icon */
  loading?: IconValue;
  /** First page icon */
  first?: IconValue;
  /** Last page icon */
  last?: IconValue;
  /** Unfold icon */
  unfold?: IconValue;
  /** File icon */
  file?: IconValue;
  /** Plus icon */
  plus?: IconValue;
  /** Minus icon */
  minus?: IconValue;
  /** Calendar icon */
  calendar?: IconValue;
}

interface IconSet {
  /** Icon component to render */
  component: Component;
  /** Default props for icon component */
  props?: IconProps;
}

interface IconProps {
  /** Icon color */
  color?: string;
  /** Icon size */
  size?: string | number;
  /** Icon tag */
  tag?: string;
  /** Icon theme */
  theme?: string;
}

type IconValue = string | [string, number] | ComponentPublicInstance;

Usage Examples:

// vuetify.js configuration
import { createVuetify } from 'vuetify';
import { aliases, mdi } from 'vuetify/iconsets/mdi';
import { fa } from 'vuetify/iconsets/fa';
import '@mdi/font/css/materialdesignicons.css';
import '@fortawesome/fontawesome-free/css/all.css';

const vuetify = createVuetify({
  icons: {
    defaultSet: 'mdi',
    aliases,
    sets: {
      mdi,
      fa,
      custom: {
        component: CustomIconComponent,
        props: {
          tag: 'i',
          size: 'default'
        }
      }
    }
  }
});

VIcon Component

Core icon display component with support for multiple icon sets and customization options.

/**
 * Icon display component
 */
const VIcon: Component;

interface IconComponentProps {
  /** Icon identifier */
  icon?: IconValue;
  /** Icon color */
  color?: string;
  /** Icon size */
  size?: string | number | 'x-small' | 'small' | 'default' | 'large' | 'x-large';
  /** Icon density */
  density?: 'default' | 'comfortable' | 'compact';
  /** Icon tag element */
  tag?: string;
  /** Icon theme */
  theme?: string;
  /** Start icon (for text direction) */
  start?: boolean;
  /** End icon (for text direction) */
  end?: boolean;
  /** Disabled state */
  disabled?: boolean;
}

// Events
interface IconEvents {
  'click': (event: MouseEvent) => void;
}

Usage Examples:

<template>
  <div>
    <!-- Basic icons -->
    <v-icon>mdi-home</v-icon>
    <v-icon icon="mdi-account" />
    <v-icon>$vuetify.icons.menu</v-icon>

    <!-- Sized icons -->
    <v-icon size="x-small">mdi-heart</v-icon>
    <v-icon size="small">mdi-heart</v-icon>
    <v-icon size="default">mdi-heart</v-icon>
    <v-icon size="large">mdi-heart</v-icon>
    <v-icon size="x-large">mdi-heart</v-icon>
    <v-icon size="64">mdi-heart</v-icon>

    <!-- Colored icons -->
    <v-icon color="primary">mdi-home</v-icon>
    <v-icon color="red">mdi-heart</v-icon>
    <v-icon color="#FF5722">mdi-favorite</v-icon>

    <!-- Clickable icons -->
    <v-icon @click="handleClick">mdi-menu</v-icon>

    <!-- Icons in buttons -->
    <v-btn icon>
      <v-icon>mdi-heart</v-icon>
    </v-btn>

    <v-btn prepend-icon="mdi-account" append-icon="mdi-chevron-down">
      User Menu
    </v-btn>

    <!-- Font Awesome icons -->
    <v-icon>fas fa-home</v-icon>
    <v-icon>fab fa-vuejs</v-icon>

    <!-- Custom icon component -->
    <v-icon icon="custom:my-icon" />

    <!-- Dynamic icons -->
    <v-icon :icon="currentIcon" :color="iconColor" />
  </div>
</template>

<script setup>
const currentIcon = ref('mdi-home');
const iconColor = ref('primary');

const handleClick = () => {
  console.log('Icon clicked');
};

const cycleIcon = () => {
  const icons = ['mdi-home', 'mdi-account', 'mdi-settings', 'mdi-heart'];
  const currentIndex = icons.indexOf(currentIcon.value);
  currentIcon.value = icons[(currentIndex + 1) % icons.length];
};
</script>

Icon Sets

Pre-configured icon sets for different icon libraries with optimized loading and rendering.

/**
 * Material Design Icons (MDI) icon set
 */
interface MdiIconSet extends IconSet {
  component: Component;
  props: {
    tag: 'i';
    class: 'mdi';
  };
}

/**
 * Font Awesome icon set
 */
interface FontAwesomeIconSet extends IconSet {
  component: Component;
  props: {
    tag: 'i';
    class: string;
  };
}

/**
 * Material Design (Google) icon set
 */
interface MaterialIconSet extends IconSet {
  component: Component;
  props: {
    tag: 'i';
    class: 'material-icons';
  };
}

/**
 * SVG icon set for custom implementations
 */
interface SvgIconSet extends IconSet {
  component: Component;
  props: {
    tag: 'svg';
    viewBox: '0 0 24 24';
  };
}

// Available icon sets
const mdi: MdiIconSet;
const fa: FontAwesomeIconSet;
const fa4: FontAwesomeIconSet; // Font Awesome 4 compatibility
const faSvg: SvgIconSet; // Font Awesome SVG
const md: MaterialIconSet; // Google Material Design
const mdiSvg: SvgIconSet; // MDI SVG format

Usage Examples:

<template>
  <div>
    <!-- Material Design Icons -->
    <v-card class="mb-4">
      <v-card-title>
        <v-icon>mdi-palette</v-icon>
        Material Design Icons
      </v-card-title>
      <v-card-text>
        <div class="icon-grid">
          <div v-for="icon in mdiIcons" :key="icon.name" class="icon-item">
            <v-icon :size="32">{{ icon.name }}</v-icon>
            <span class="icon-label">{{ icon.label }}</span>
          </div>
        </div>
      </v-card-text>
    </v-card>

    <!-- Font Awesome Icons -->
    <v-card class="mb-4">
      <v-card-title>
        <v-icon>fab fa-font-awesome</v-icon>
        Font Awesome Icons
      </v-card-title>
      <v-card-text>
        <div class="icon-grid">
          <div v-for="icon in faIcons" :key="icon.name" class="icon-item">
            <v-icon :size="32">{{ icon.name }}</v-icon>
            <span class="icon-label">{{ icon.label }}</span>
          </div>
        </div>
      </v-card-text>
    </v-card>

    <!-- Google Material Icons -->
    <v-card class="mb-4">
      <v-card-title>
        <v-icon>md:home</v-icon>
        Google Material Icons
      </v-card-title>
      <v-card-text>
        <div class="icon-grid">
          <div v-for="icon in materialIcons" :key="icon.name" class="icon-item">
            <v-icon :size="32">{{ icon.name }}</v-icon>
            <span class="icon-label">{{ icon.label }}</span>
          </div>
        </div>
      </v-card-text>
    </v-card>

    <!-- SVG Icons -->
    <v-card class="mb-4">
      <v-card-title>
        <CustomSvgIcon />
        Custom SVG Icons
      </v-card-title>
      <v-card-text>
        <div class="icon-grid">
          <div v-for="icon in svgIcons" :key="icon.name" class="icon-item">
            <component :is="icon.component" :size="32" />
            <span class="icon-label">{{ icon.label }}</span>
          </div>
        </div>
      </v-card-text>
    </v-card>

    <!-- Icon set comparison -->
    <v-card>
      <v-card-title>Icon Set Comparison</v-card-title>
      <v-card-text>
        <v-simple-table>
          <template #default>
            <thead>
              <tr>
                <th>Icon Set</th>
                <th>Format</th>
                <th>Size</th>
                <th>Icons Count</th>
                <th>Example</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>Material Design Icons</td>
                <td>Font/SVG</td>
                <td>~500KB</td>
                <td>7000+</td>
                <td><v-icon>mdi-vuetify</v-icon></td>
              </tr>
              <tr>
                <td>Font Awesome</td>
                <td>Font/SVG</td>
                <td>~400KB</td>
                <td>1600+</td>
                <td><v-icon>fas fa-star</v-icon></td>
              </tr>
              <tr>
                <td>Google Material</td>
                <td>Font</td>
                <td>~50KB</td>
                <td>1000+</td>
                <td><v-icon>md:star</v-icon></td>
              </tr>
              <tr>
                <td>Custom SVG</td>
                <td>SVG</td>
                <td>Varies</td>
                <td>Custom</td>
                <td><CustomSvgIcon size="24" /></td>
              </tr>
            </tbody>
          </template>
        </v-simple-table>
      </v-card-text>
    </v-card>
  </div>
</template>

<script setup>
const mdiIcons = [
  { name: 'mdi-home', label: 'Home' },
  { name: 'mdi-account', label: 'Account' },
  { name: 'mdi-settings', label: 'Settings' },
  { name: 'mdi-heart', label: 'Heart' },
  { name: 'mdi-star', label: 'Star' },
  { name: 'mdi-check', label: 'Check' },
  { name: 'mdi-close', label: 'Close' },
  { name: 'mdi-menu', label: 'Menu' },
  { name: 'mdi-search', label: 'Search' },
  { name: 'mdi-shopping', label: 'Shopping' }
];

const faIcons = [
  { name: 'fas fa-home', label: 'Home' },
  { name: 'fas fa-user', label: 'User' },
  { name: 'fas fa-cog', label: 'Settings' },
  { name: 'fas fa-heart', label: 'Heart' },
  { name: 'fas fa-star', label: 'Star' },
  { name: 'fas fa-check', label: 'Check' },
  { name: 'fas fa-times', label: 'Close' },
  { name: 'fas fa-bars', label: 'Menu' },
  { name: 'fas fa-search', label: 'Search' },
  { name: 'fas fa-shopping-cart', label: 'Shopping' }
];

const materialIcons = [
  { name: 'md:home', label: 'Home' },
  { name: 'md:person', label: 'Person' },
  { name: 'md:settings', label: 'Settings' },
  { name: 'md:favorite', label: 'Favorite' },
  { name: 'md:star', label: 'Star' },
  { name: 'md:check', label: 'Check' },
  { name: 'md:close', label: 'Close' },
  { name: 'md:menu', label: 'Menu' },
  { name: 'md:search', label: 'Search' },
  { name: 'md:shopping_cart', label: 'Shopping' }
];

const svgIcons = [
  { name: 'custom-icon-1', label: 'Custom 1', component: CustomIcon1 },
  { name: 'custom-icon-2', label: 'Custom 2', component: CustomIcon2 },
];
</script>

<style>
.icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: 16px;
}

.icon-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 16px;
  border-radius: 8px;
  background: rgba(0,0,0,0.02);
  transition: background-color 0.2s;
}

.icon-item:hover {
  background: rgba(0,0,0,0.05);
}

.icon-label {
  font-size: 0.75rem;
  text-align: center;
  color: rgba(0,0,0,0.6);
}
</style>

Custom Icon Implementation

Creating and registering custom icon sets and components for specialized use cases.

/**
 * Custom icon component interface
 */
interface CustomIconComponent {
  /** Icon name or identifier */
  name?: string;
  /** Icon size */
  size?: string | number;
  /** Icon color */
  color?: string;
  /** Additional CSS classes */
  class?: string | string[];
  /** Inline styles */
  style?: Record<string, any>;
  /** Accessibility label */
  'aria-label'?: string;
  /** Icon title for tooltips */
  title?: string;
}

/**
 * SVG icon definition
 */
interface SvgIconDefinition {
  /** SVG path data */
  path: string;
  /** ViewBox dimensions */
  viewBox?: string;
  /** Icon width */
  width?: number;
  /** Icon height */
  height?: number;
}

/**
 * Icon registry for custom icons
 */
interface IconRegistry {
  /** Register new icon */
  register: (name: string, definition: SvgIconDefinition | Component) => void;
  /** Unregister icon */
  unregister: (name: string) => void;
  /** Get icon definition */
  get: (name: string) => SvgIconDefinition | Component | undefined;
  /** List all registered icons */
  list: () => string[];
}

Usage Examples:

<template>
  <div>
    <!-- Custom SVG icon component -->
    <svg-icon name="custom-logo" :size="48" color="primary" />

    <!-- Custom icon with animation -->
    <animated-icon name="loading-spinner" :size="32" />

    <!-- Icon with custom styling -->
    <custom-icon
      name="brand-icon"
      :size="40"
      :style="{ filter: 'drop-shadow(2px 2px 4px rgba(0,0,0,0.3))' }"
    />

    <!-- Custom icon gallery -->
    <v-card>
      <v-card-title>Custom Icons</v-card-title>
      <v-card-text>
        <div class="custom-icon-grid">
          <div
            v-for="icon in customIcons"
            :key="icon.name"
            class="custom-icon-item"
          >
            <component
              :is="icon.component"
              :name="icon.name"
              :size="48"
              :color="icon.color"
            />
            <span>{{ icon.label }}</span>
          </div>
        </div>
      </v-card-text>
    </v-card>
  </div>
</template>

<script setup>
// Custom SVG Icon Component
const SvgIcon = defineComponent({
  props: {
    name: String,
    size: {
      type: [String, Number],
      default: 24
    },
    color: {
      type: String,
      default: 'currentColor'
    }
  },
  setup(props) {
    const iconDefinitions = {
      'custom-logo': {
        path: 'M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5',
        viewBox: '0 0 24 24'
      },
      'brand-icon': {
        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',
        viewBox: '0 0 24 24'
      }
    };

    const iconDef = computed(() => iconDefinitions[props.name]);

    return () => {
      if (!iconDef.value) return null;

      return h('svg', {
        width: props.size,
        height: props.size,
        viewBox: iconDef.value.viewBox,
        fill: props.color,
        class: 'custom-svg-icon'
      }, [
        h('path', { d: iconDef.value.path })
      ]);
    };
  }
});

// Animated Icon Component
const AnimatedIcon = defineComponent({
  props: {
    name: String,
    size: {
      type: [String, Number],
      default: 24
    }
  },
  setup(props) {
    const animations = {
      'loading-spinner': {
        path: 'M12,4V2A10,10 0 0,0 2,12H4A8,8 0 0,1 12,4Z',
        animation: 'spin 1s linear infinite'
      },
      'pulse-heart': {
        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',
        animation: 'pulse 2s ease-in-out infinite'
      }
    };

    const iconDef = computed(() => animations[props.name]);

    return () => {
      if (!iconDef.value) return null;

      return h('svg', {
        width: props.size,
        height: props.size,
        viewBox: '0 0 24 24',
        fill: 'currentColor',
        style: {
          animation: iconDef.value.animation
        },
        class: 'animated-icon'
      }, [
        h('path', { d: iconDef.value.path })
      ]);
    };
  }
});

const customIcons = [
  { 
    name: 'custom-logo', 
    label: 'Custom Logo', 
    component: SvgIcon, 
    color: 'primary' 
  },
  { 
    name: 'brand-icon', 
    label: 'Brand Icon', 
    component: SvgIcon, 
    color: 'success' 
  },
  { 
    name: 'loading-spinner', 
    label: 'Loading', 
    component: AnimatedIcon, 
    color: 'info' 
  },
  { 
    name: 'pulse-heart', 
    label: 'Pulse Heart', 
    component: AnimatedIcon, 
    color: 'error' 
  }
];
</script>

<style>
@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.2); }
}

.custom-icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 20px;
}

.custom-icon-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  padding: 20px;
  border-radius: 12px;
  background: rgba(0,0,0,0.02);
  transition: all 0.3s ease;
}

.custom-icon-item:hover {
  background: rgba(0,0,0,0.05);
  transform: translateY(-2px);
}

.animated-icon {
  transform-origin: center;
}

.custom-svg-icon {
  transition: all 0.2s ease;
}
</style>

Icon Loading and Performance

Optimization strategies for icon loading, bundle size management, and performance considerations.

/**
 * Icon loading strategies
 */
interface IconLoadingOptions {
  /** Lazy load icons */
  lazy?: boolean;
  /** Preload critical icons */
  preload?: string[];
  /** Icon bundle splitting */
  bundles?: IconBundle[];
  /** Cache configuration */
  cache?: IconCacheOptions;
}

interface IconBundle {
  /** Bundle name */
  name: string;
  /** Icons in bundle */
  icons: string[];
  /** Loading strategy */
  strategy: 'eager' | 'lazy' | 'preload';
}

interface IconCacheOptions {
  /** Cache duration in milliseconds */
  duration?: number;
  /** Maximum cache size */
  maxSize?: number;
  /** Storage type */
  storage?: 'memory' | 'localStorage' | 'sessionStorage';
}

/**
 * Tree shaking support for icons
 */
interface TreeShakableIconSet {
  /** Only include used icons */
  treeShake: boolean;
  /** Icon usage tracking */
  usage?: IconUsageTracker;
}

interface IconUsageTracker {
  /** Track icon usage */
  track: (iconName: string) => void;
  /** Get usage statistics */
  getStats: () => IconUsageStats;
  /** Reset tracking data */
  reset: () => void;
}

interface IconUsageStats {
  /** Total icons used */
  totalUsed: number;
  /** Most used icons */
  mostUsed: Array<{ name: string; count: number }>;
  /** Unused icons */
  unused: string[];
}

Usage Examples:

// Optimized icon configuration
import { createVuetify } from 'vuetify';

// Tree-shaken icon imports (only imports used icons)
import {
  mdiHome,
  mdiAccount,
  mdiSettings,
  mdiHeart,
  mdiStar
} from '@mdi/js';

// Custom icon set with tree shaking
const optimizedMdi = {
  component: (props) => h(SvgIcon, props),
  props: {
    tag: 'svg'
  },
  // Define only the icons you need
  icons: {
    home: mdiHome,
    account: mdiAccount,
    settings: mdiSettings,
    heart: mdiHeart,
    star: mdiStar
  }
};

const vuetify = createVuetify({
  icons: {
    defaultSet: 'optimizedMdi',
    sets: {
      optimizedMdi
    }
  }
});

// Lazy loading icon strategy
const lazyIconLoader = {
  async loadIcon(iconName) {
    // Dynamic import for unused icons
    const iconModule = await import(`@mdi/js/${iconName}`);
    return iconModule[iconName];
  },
  
  cache: new Map(),
  
  async getIcon(iconName) {
    if (this.cache.has(iconName)) {
      return this.cache.get(iconName);
    }
    
    const iconData = await this.loadIcon(iconName);
    this.cache.set(iconName, iconData);
    return iconData;
  }
};

// Performance monitoring
const iconPerformanceMonitor = {
  startTimes: new Map(),
  
  startLoad(iconName) {
    this.startTimes.set(iconName, performance.now());
  },
  
  endLoad(iconName) {
    const startTime = this.startTimes.get(iconName);
    if (startTime) {
      const loadTime = performance.now() - startTime;
      console.log(`Icon ${iconName} loaded in ${loadTime.toFixed(2)}ms`);
      this.startTimes.delete(iconName);
    }
  }
};

Types

// Core icon types
type IconIdentifier = string;
type IconSize = 'x-small' | 'small' | 'default' | 'large' | 'x-large' | number | string;
type IconColor = string;

// Icon value types
type IconValue = 
  | string                              // Icon name: 'mdi-home'
  | [string, number]                   // Icon with rotation: ['mdi-home', 90]
  | ComponentPublicInstance;           // Custom component

// Icon set types
type IconSetName = 'mdi' | 'fa' | 'fa4' | 'fa-svg' | 'md' | 'mdi-svg' | string;

// Icon format types
type IconFormat = 'font' | 'svg' | 'component';

// Icon component types
interface IconComponentType {
  name: string;
  props: Record<string, any>;
  render: () => VNode;
}

// Accessibility types
interface IconAccessibility {
  label?: string;
  describedBy?: string;
  hidden?: boolean;
  role?: string;
}

// Icon state types
type IconState = 'loading' | 'loaded' | 'error' | 'cached';

// Icon metrics
interface IconMetrics {
  loadTime: number;
  renderTime: number;
  cacheHit: boolean;
  bundleSize: number;
}

// Icon theme integration
interface IconTheme {
  colors: Record<string, string>;
  sizes: Record<string, number>;
  variants: Record<string, IconProps>;
}

Install with Tessl CLI

npx tessl i tessl/npm-vuetify

docs

components.md

composables.md

data-display.md

directives.md

feedback.md

forms.md

framework-core.md

icons.md

index.md

internationalization.md

lab-components.md

navigation.md

theming.md

transitions.md

utilities.md

tile.json