UIPackage
Menu

Framework

Change language

Boilerplate repo

List

list ui
Boilerplate repo

Plain content list with `<ul>` / `<li>` semantics. List, ListItem, and ListSubheader for menu items, navigation lists, or any vertical sequence of small rows. Supports active/disabled states and polymorphic as props.

Also available for React ->

Installation

$ npx shadcn-vue@latest add https://uipkge.dev/r/vue/list.json
Named registry: npx shadcn-vue@latest add @uipkge/list Installs to: app/components/ui/list/

Examples

Loading interactive previews…

Props

Name Type / Values Default Required
class HTMLAttributes['class'] optional
as
'ul''ol''div'
optional

Files installed (4)

  • app/components/ui/list/List.vue 0.4 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
      as?: 'ul' | 'ol' | 'div'
    }>()
    </script>
    
    <template>
      <component
        :is="props.as ?? 'ul'"
        data-uipkge
        data-slot="list"
        :class="cn('list-none space-y-1', props.class)"
        v-bind="$attrs"
      >
        <slot />
      </component>
    </template>
  • app/components/ui/list/ListItem.vue 1.4 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { computed, useAttrs } from 'vue'
    import { cn } from '@/lib/utils'
    
    defineOptions({ inheritAttrs: false })
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
      as?: 'li' | 'div' | 'a'
      active?: boolean
      disabled?: boolean
    }>()
    
    const attrs = useAttrs()
    
    // Only show pointer/hover affordances when the item is actually interactive.
    const isInteractive = computed(() => {
      if (props.disabled) return false
      if ((props.as ?? 'li') === 'a') return true
      if (attrs.href != null && attrs.href !== false) return true
      if (typeof attrs.onClick === 'function') return true
      return false
    })
    </script>
    
    <template>
      <component
        :is="props.as ?? 'li'"
        data-uipkge
        data-slot="list-item"
        :data-active="active ? '' : undefined"
        :data-disabled="disabled ? '' : undefined"
        :aria-disabled="disabled ? 'true' : undefined"
        :aria-current="active ? 'true' : undefined"
        :tabindex="disabled ? -1 : undefined"
        :class="
          cn(
            'rounded-md px-2 py-1.5 text-sm transition-colors duration-200 select-none focus-visible:outline-none',
            !disabled && isInteractive && 'hover:bg-accent focus-visible:bg-accent cursor-pointer',
            active && 'bg-accent text-accent-foreground',
            disabled && 'pointer-events-none cursor-not-allowed opacity-50',
            props.class,
          )
        "
        v-bind="$attrs"
      >
        <slot />
      </component>
    </template>
  • app/components/ui/list/ListSubheader.vue 0.5 kB
    <script setup lang="ts">
    import type { HTMLAttributes } from 'vue'
    import { cn } from '@/lib/utils'
    
    const props = defineProps<{
      class?: HTMLAttributes['class']
      inset?: boolean
    }>()
    </script>
    
    <template>
      <li
        data-uipkge
        data-slot="list-subheader"
        :class="
          cn(
            'text-muted-foreground px-2 py-1.5 text-xs font-semibold tracking-wide uppercase',
            inset && 'pl-8',
            props.class,
          )
        "
        v-bind="$attrs"
      >
        <slot />
      </li>
    </template>
  • app/components/ui/list/index.ts 0.2 kB
    export { default as List } from './List.vue'
    export { default as ListItem } from './ListItem.vue'
    export { default as ListSubheader } from './ListSubheader.vue'

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