UIPackage

Icons

Vue data-display
Edit on GitHub

Showcase + recipe page for the registry’s default icon set (Lucide). Not a runtime component — install the npm package directly. Documented here so consumers can browse names and copy-paste imports.

Also available for React ->

Installation

$ npx shadcn-vue@latest add https://uipkge.dev/r/vue/icons.json

Or with the named registry: npx shadcn-vue@latest add @uipkge/icons

Examples

Props

Name Type / Values Default Required
size

Size

'xs''sm''md''lg''xl''2xl''inherit'
'md' optional
color

Color

string optional
class

Custom class for icon libraries (fa-, mdi-, etc.)

HTMLAttributes['class'] optional
src

For img-based icons

string optional
alt string optional
rotation

Rotation/flip

number | string optional
flip
'horizontal''vertical''both'
optional
label

A11y

string optional
ariaLabel string optional
inline

Style

boolean true optional

Files (2)

  • app/components/ui/icons/Icon.vue 2.4 kB
    <script setup lang="ts">
    import { computed } from 'vue'
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    /**
     * Universal Icon component supporting multiple icon libraries:
     * - Lucide (default, via slot)
     * - Font Awesome (via class:fa-* and :class)
     * - Material Design Icons (via class:mdi-* and :class)
     * - Heroicons (via slot)
     * - Custom SVG (via src prop)
     */
    const props = withDefaults(
      defineProps<{
        // Size
        size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'inherit'
        // Color
        color?: string
        // Custom class for icon libraries (fa-, mdi-, etc.)
        class?: HTMLAttributes['class']
        // For img-based icons
        src?: string
        alt?: string
        // Rotation/flip
        rotation?: number | string
        flip?: 'horizontal' | 'vertical' | 'both'
        // A11y
        label?: string
        ariaLabel?: string
        // Style
        inline?: boolean
      }>(),
      {
        size: 'md',
        inline: true,
      },
    )
    
    const sizeClasses = {
      xs: 'size-3',
      sm: 'size-4',
      md: 'size-5',
      lg: 'size-6',
      xl: 'size-8',
      '2xl': 'size-12',
      inherit: 'size-full',
    }
    
    const rotationDeg = computed(() => {
      if (!props.rotation) return undefined
      return typeof props.rotation === 'string' ? parseInt(props.rotation) : props.rotation
    })
    
    const flipClasses = computed(() => {
      if (!props.flip) return ''
      if (props.flip === 'horizontal') return '-scale-x-100'
      if (props.flip === 'vertical') return '-scale-y-100'
      if (props.flip === 'both') return '-scale-x-100 -scale-y-100'
      return ''
    })
    </script>
    
    <template>
      <!-- Image-based icon (Material Design, custom URLs, etc.) -->
      <img
        v-if="src"
        :src="src"
        :alt="alt || label"
        :class="cn('shrink-0 object-contain', size !== 'inherit' ? sizeClasses[size] : '', flipClasses, props.class)"
        :style="{
          color: color,
          transform: rotationDeg ? `rotate(${rotationDeg}deg)` : undefined,
        }"
        :aria-label="ariaLabel || label"
        role="img"
      />
    
      <!-- Slot-based icon (Lucide, Heroicons, inline SVG) -->
      <span
        v-else
        :class="
          cn(
            'inline-flex shrink-0 items-center justify-center',
            size !== 'inherit' ? sizeClasses[size] : '',
            flipClasses,
            props.class,
          )
        "
        :style="{
          color: color,
          transform: rotationDeg ? `rotate(${rotationDeg}deg)` : undefined,
        }"
        :aria-label="ariaLabel || label"
        :role="label ? 'img' : undefined"
      >
        <slot />
      </span>
    </template>
  • app/components/ui/icons/index.ts 0.6 kB
    export { default as Icon } from './Icon.vue'
    
    // Icon library class prefixes for reference:
    // Font Awesome: 'fa-solid', 'fa-regular', 'fa-brands', 'fa-*'
    // Material Design: 'mdi mdi-*'
    // Heroicons: already SVG-based, use slot
    
    // Helper function to generate Font Awesome class
    export function faClass(iconName: string, style: 'solid' | 'regular' | 'brands' = 'solid'): string {
      const prefix = style === 'brands' ? 'fab' : style === 'solid' ? 'fas' : 'far'
      return `${prefix} fa-${iconName}`
    }
    
    // Helper function to generate Material Design class
    export function mdiClass(iconName: string): string {
      return `mdi mdi-${iconName}`
    }

Raw manifest: https://uipkge.dev/r/vue/icons.json