List
listuiList and Item row primitives with List, ListItem, ListItemMedia, ListItemContent, ListItemTitle, ListItemDescription, ListItemActions, and ListSubheader for structured rows, settings lists, and feeds.
Installation
$pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/list.json$npx shadcn-vue@latest add https://uipkge.dev/r/vue/list.json$yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/list.json$bunx shadcn-vue@latest add https://uipkge.dev/r/vue/list.jsonNamed registry:
npx shadcn-vue@latest add @uipkge/listInstalls to:app/components/ui/list/Examples
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
class | HTMLAttributes['class'] | — | optional |
as | 'ul''ol''div' | — | optional |
Files installed (9)
app/components/ui/list/List.vue0.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.vue1.6 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', 'has-[>[data-slot=list-item-content]]:flex has-[>[data-slot=list-item-content]]:items-center has-[>[data-slot=list-item-content]]:gap-3', !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/ListItemMedia.vue0.4 kB
<script setup lang="ts"> import type { HTMLAttributes } from 'vue' import { cn } from '@/lib/utils' interface Props { class?: HTMLAttributes['class'] } const props = defineProps<Props>() </script> <template> <div data-uipkge data-slot="list-item-media" :class="cn('flex shrink-0 items-center justify-center self-center', props.class)" > <slot /> </div> </template>app/components/ui/list/ListItemContent.vue0.4 kB
<script setup lang="ts"> import type { HTMLAttributes } from 'vue' import { cn } from '@/lib/utils' interface Props { class?: HTMLAttributes['class'] } const props = defineProps<Props>() </script> <template> <div data-uipkge data-slot="list-item-content" :class="cn('flex min-w-0 flex-1 flex-col gap-0.5 self-center', props.class)" > <slot /> </div> </template>app/components/ui/list/ListItemTitle.vue0.4 kB
<script setup lang="ts"> import type { HTMLAttributes } from 'vue' import { cn } from '@/lib/utils' interface Props { class?: HTMLAttributes['class'] } const props = defineProps<Props>() </script> <template> <div data-uipkge data-slot="list-item-title" :class="cn('text-foreground truncate text-sm leading-none font-medium', props.class)" > <slot /> </div> </template>app/components/ui/list/ListItemDescription.vue0.4 kB
<script setup lang="ts"> import type { HTMLAttributes } from 'vue' import { cn } from '@/lib/utils' interface Props { class?: HTMLAttributes['class'] } const props = defineProps<Props>() </script> <template> <div data-uipkge data-slot="list-item-description" :class="cn('text-muted-foreground line-clamp-1 text-xs', props.class)" > <slot /> </div> </template>app/components/ui/list/ListItemActions.vue0.4 kB
<script setup lang="ts"> import type { HTMLAttributes } from 'vue' import { cn } from '@/lib/utils' interface Props { class?: HTMLAttributes['class'] } const props = defineProps<Props>() </script> <template> <div data-uipkge data-slot="list-item-actions" :class="cn('text-muted-foreground flex shrink-0 items-center gap-1.5 self-center', props.class)" > <slot /> </div> </template>app/components/ui/list/ListSubheader.vue0.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.ts0.5 kB
export { default as List } from './List.vue' export { default as ListItem } from './ListItem.vue' export { default as ListItemMedia } from './ListItemMedia.vue' export { default as ListItemContent } from './ListItemContent.vue' export { default as ListItemTitle } from './ListItemTitle.vue' export { default as ListItemDescription } from './ListItemDescription.vue' export { default as ListItemActions } from './ListItemActions.vue' export { default as ListSubheader } from './ListSubheader.vue'
Raw manifest:https://uipkge.dev/r/vue/list.json