Una lista seleccionable de elementos con búsqueda, virtualización y renderización de elementos enriquecidos.

xph0000xUso

Utilice la directiva v-model para controlar el valor del Listbox o la prop default-value para establecer el valor inicial cuando no necesite controlar su estado.

France
Germany
Italy
Spain
Netherlands
Poland
Belgium
Portugal
Austria
Sweden
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  },
  {
    label: 'Netherlands',
    icon: 'i-lucide-map-pin',
    value: 'NL'
  },
  {
    label: 'Poland',
    icon: 'i-lucide-map-pin',
    value: 'PL'
  },
  {
    label: 'Belgium',
    icon: 'i-lucide-map-pin',
    value: 'BE'
  },
  {
    label: 'Portugal',
    icon: 'i-lucide-map-pin',
    value: 'PT'
  },
  {
    label: 'Austria',
    icon: 'i-lucide-map-pin',
    value: 'AT'
  },
  {
    label: 'Sweden',
    icon: 'i-lucide-map-pin',
    value: 'SE'
  }
])
const value = ref({
  label: 'France',
  icon: 'i-lucide-map-pin',
  value: 'FR'
})
</script>

<template>
  <UListbox v-model="value" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  },
  {
    label: 'Netherlands',
    icon: 'i-lucide-map-pin',
    value: 'NL'
  },
  {
    label: 'Poland',
    icon: 'i-lucide-map-pin',
    value: 'PL'
  },
  {
    label: 'Belgium',
    icon: 'i-lucide-map-pin',
    value: 'BE'
  },
  {
    label: 'Portugal',
    icon: 'i-lucide-map-pin',
    value: 'PT'
  },
  {
    label: 'Austria',
    icon: 'i-lucide-map-pin',
    value: 'AT'
  },
  {
    label: 'Sweden',
    icon: 'i-lucide-map-pin',
    value: 'SE'
  }
])
const value = ref({
  label: 'France',
  icon: 'i-lucide-map-pin',
  value: 'FR'
})
</script>

<template>
  <UListbox v-model="value" :items="items" />
</template>

Artículos

Utilice el prop items como una matriz de objetos con las siguientes propiedades:

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

  • xxonSelect?: (e: Event) => voidxx{lang="ts-type"}
  • xclass?: anyx{lang="ts-type"} (Edición española)
  • xui?: { label?: ClassNameValue, separator?: ClassNameValue, item?: ClassNameValue, itemLeadingIcon?: ClassNameValue, ... }x{lang="ts-type"}
FranceThe Hexagon
GermanyThe Federal Republic
ItalyThe Boot
SpainThe Bull Skin
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    description: 'The Hexagon',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    description: 'The Federal Republic',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    description: 'The Boot',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    description: 'The Bull Skin',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    description: 'The Hexagon',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    description: 'The Federal Republic',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    description: 'The Boot',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    description: 'The Bull Skin',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>

También puede pasar una matriz de matrices al soporte items para mostrar grupos separados de elementos.

France
Germany
Italy
Brazil
Argentina
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[][]>([
  [
    {
      label: 'France',
      icon: 'i-lucide-map-pin',
      value: 'FR'
    },
    {
      label: 'Germany',
      icon: 'i-lucide-map-pin',
      value: 'DE'
    },
    {
      label: 'Italy',
      icon: 'i-lucide-map-pin',
      value: 'IT'
    }
  ],
  [
    {
      label: 'Brazil',
      icon: 'i-lucide-map-pin',
      value: 'BR'
    },
    {
      label: 'Argentina',
      icon: 'i-lucide-map-pin',
      value: 'AR'
    }
  ]
])
</script>

<template>
  <UListbox :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[][]>([
  [
    {
      label: 'France',
      icon: 'i-lucide-map-pin',
      value: 'FR'
    },
    {
      label: 'Germany',
      icon: 'i-lucide-map-pin',
      value: 'DE'
    },
    {
      label: 'Italy',
      icon: 'i-lucide-map-pin',
      value: 'IT'
    }
  ],
  [
    {
      label: 'Brazil',
      icon: 'i-lucide-map-pin',
      value: 'BR'
    },
    {
      label: 'Argentina',
      icon: 'i-lucide-map-pin',
      value: 'AR'
    }
  ]
])
</script>

<template>
  <UListbox :items="items" />
</template>

Multiplicación

Utilice el prop multiple para permitir la selección de varios elementos. Cuando esté habilitado, el v-model será una matriz.

France
Germany
Italy
Spain
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox multiple :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox multiple :items="items" />
</template>

Value Clave de seguridad

Puede optar por vincular una sola propiedad del objeto en lugar de todo el objeto utilizando la prop. value-key.

France
Germany
Italy
Spain
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
const value = ref('FR')
</script>

<template>
  <UListbox v-model="value" value-key="value" :items="items" class="w-full" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
const value = ref('FR')
</script>

<template>
  <UListbox v-model="value" value-key="value" :items="items" class="w-full" />
</template>

Filter (Edición española)

Utilice el prop filter para mostrar una entrada de filtro o pasar un objeto para personalizar el componente Input.

France
Germany
Italy
Spain
Netherlands
Poland
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  },
  {
    label: 'Netherlands',
    icon: 'i-lucide-map-pin',
    value: 'NL'
  },
  {
    label: 'Poland',
    icon: 'i-lucide-map-pin',
    value: 'PL'
  }
])
</script>

<template>
  <UListbox :filter="{
  placeholder: 'Filter...',
  icon: 'i-lucide-search'
}" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  },
  {
    label: 'Netherlands',
    icon: 'i-lucide-map-pin',
    value: 'NL'
  },
  {
    label: 'Poland',
    icon: 'i-lucide-map-pin',
    value: 'PL'
  }
])
</script>

<template>
  <UListbox :filter="{
  placeholder: 'Filter...',
  icon: 'i-lucide-search'
}" :items="items" />
</template>

Icono seleccionado

Utilice el prop selected-icon para personalizar el icono cuando se selecciona un elemento.

France
Germany
Italy
Spain
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
const value = ref('FR')
</script>

<template>
  <UListbox v-model="value" selected-icon="i-lucide-flame" value-key="value" :items="items" class="w-full" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
const value = ref('FR')
</script>

<template>
  <UListbox v-model="value" selected-icon="i-lucide-flame" value-key="value" :items="items" class="w-full" />
</template>

Tamaño

Utilice el accesorio size para cambiar el tamaño del Listbox.

France
Germany
Italy
Spain
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox size="xl" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox size="xl" :items="items" />
</template>

Cargando

Utilice el accesorio loading para mostrar un indicador de carga. Use el accesorio loading-icon para personalizar el icono.

<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  }
])
</script>

<template>
  <UListbox loading :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  }
])
</script>

<template>
  <UListbox loading :items="items" />
</template>

Desactivado

Utilice el accesorio disabled para evitar cualquier interacción del usuario con el Listbox.

France
Germany
Italy
Spain
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox disabled :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox disabled :items="items" />
</template>

Ejemplos

Con tipo de elementos

Puede utilizar la propiedad type con separator para mostrar un separador entre elementos o label para mostrar una etiqueta.

Fruits
Apple
Banana
Blueberry
Grapes
Pineapple
Vegetables
Aubergine
Broccoli
Carrot
Courgette
Leek
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[][]>([
  [
    {
      type: 'label',
      label: 'Fruits'
    },
    {
      label: 'Apple'
    },
    {
      label: 'Banana'
    },
    {
      label: 'Blueberry'
    },
    {
      label: 'Grapes'
    },
    {
      label: 'Pineapple'
    }
  ],
  [
    {
      type: 'label',
      label: 'Vegetables'
    },
    {
      label: 'Aubergine'
    },
    {
      label: 'Broccoli'
    },
    {
      label: 'Carrot'
    },
    {
      label: 'Courgette'
    },
    {
      label: 'Leek'
    }
  ]
])
</script>

<template>
  <UListbox :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[][]>([
  [
    {
      type: 'label',
      label: 'Fruits'
    },
    {
      label: 'Apple'
    },
    {
      label: 'Banana'
    },
    {
      label: 'Blueberry'
    },
    {
      label: 'Grapes'
    },
    {
      label: 'Pineapple'
    }
  ],
  [
    {
      type: 'label',
      label: 'Vegetables'
    },
    {
      label: 'Aubergine'
    },
    {
      label: 'Broccoli'
    },
    {
      label: 'Carrot'
    },
    {
      label: 'Courgette'
    },
    {
      label: 'Leek'
    }
  ]
])
</script>

<template>
  <UListbox :items="items" />
</template>
Al usar elementos label como encabezados de grupo, pase una matriz de matrices para que una etiqueta se filtre junto con su grupo al realizar una búsqueda.

Con icono en elementos

Puede usar la propiedad icon para mostrar un Icon dentro de los elementos.

Backlog
Todo
In Progress
Done
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'Backlog',
    icon: 'i-lucide-circle-help',
    value: 'backlog'
  },
  {
    label: 'Todo',
    icon: 'i-lucide-circle-plus',
    value: 'todo'
  },
  {
    label: 'In Progress',
    icon: 'i-lucide-circle-arrow-up',
    value: 'in_progress'
  },
  {
    label: 'Done',
    icon: 'i-lucide-circle-check',
    value: 'done'
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'Backlog',
    icon: 'i-lucide-circle-help',
    value: 'backlog'
  },
  {
    label: 'Todo',
    icon: 'i-lucide-circle-plus',
    value: 'todo'
  },
  {
    label: 'In Progress',
    icon: 'i-lucide-circle-arrow-up',
    value: 'in_progress'
  },
  {
    label: 'Done',
    icon: 'i-lucide-circle-check',
    value: 'done'
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>

Con avatar en los elementos

Puede usar la propiedad avatar para mostrar un Avatar dentro de los elementos.

benjamincanac
HugoRCD
atinux
romhml
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png'
    }
  },
  {
    label: 'HugoRCD',
    avatar: {
      src: 'https://github.com/HugoRCD.png'
    }
  },
  {
    label: 'atinux',
    avatar: {
      src: 'https://github.com/atinux.png'
    }
  },
  {
    label: 'romhml',
    avatar: {
      src: 'https://github.com/romhml.png'
    }
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png'
    }
  },
  {
    label: 'HugoRCD',
    avatar: {
      src: 'https://github.com/HugoRCD.png'
    }
  },
  {
    label: 'atinux',
    avatar: {
      src: 'https://github.com/atinux.png'
    }
  },
  {
    label: 'romhml',
    avatar: {
      src: 'https://github.com/romhml.png'
    }
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>

Con chip en artículos

Puede utilizar la propiedad chip para mostrar un Chip dentro de los elementos.

bug
feature
enhancement
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'bug',
    chip: {
      color: 'error'
    }
  },
  {
    label: 'feature',
    chip: {
      color: 'success'
    }
  },
  {
    label: 'enhancement',
    chip: {
      color: 'info'
    }
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'bug',
    chip: {
      color: 'error'
    }
  },
  {
    label: 'feature',
    chip: {
      color: 'success'
    }
  },
  {
    label: 'enhancement',
    chip: {
      color: 'info'
    }
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>

Con descripción en artículos

Vous pouvez utiliser la propriété description pour afficher du texte supplémentaire sous l'étiquette.

FranceThe Hexagon
GermanyThe Federal Republic
ItalyThe Boot
SpainThe Bull Skin
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    description: 'The Hexagon',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    description: 'The Federal Republic',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    description: 'The Boot',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    description: 'The Bull Skin',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items = ref<ListboxItem[]>([
  {
    label: 'France',
    description: 'The Hexagon',
    icon: 'i-lucide-map-pin',
    value: 'FR'
  },
  {
    label: 'Germany',
    description: 'The Federal Republic',
    icon: 'i-lucide-map-pin',
    value: 'DE'
  },
  {
    label: 'Italy',
    description: 'The Boot',
    icon: 'i-lucide-map-pin',
    value: 'IT'
  },
  {
    label: 'Spain',
    description: 'The Bull Skin',
    icon: 'i-lucide-map-pin',
    value: 'ES'
  }
])
</script>

<template>
  <UListbox :items="items" />
</template>

Control artículo (s) seleccionado (s)

Puede controlar el elemento seleccionado mediante la prop default-value o la directiva v-model.

France
Germany
Italy
Spain
Netherlands
Poland
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items: ListboxItem[] = [
  { label: 'France', icon: 'i-lucide-map-pin', value: 'FR' },
  { label: 'Germany', icon: 'i-lucide-map-pin', value: 'DE' },
  { label: 'Italy', icon: 'i-lucide-map-pin', value: 'IT' },
  { label: 'Spain', icon: 'i-lucide-map-pin', value: 'ES' },
  { label: 'Netherlands', icon: 'i-lucide-map-pin', value: 'NL' },
  { label: 'Poland', icon: 'i-lucide-map-pin', value: 'PL' }
]

const value = ref<ListboxItem>(items[2]!)
</script>

<template>
  <UListbox
    v-model="value"
    :items="items"
    class="w-full"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items: ListboxItem[] = [
  { label: 'France', icon: 'i-lucide-map-pin', value: 'FR' },
  { label: 'Germany', icon: 'i-lucide-map-pin', value: 'DE' },
  { label: 'Italy', icon: 'i-lucide-map-pin', value: 'IT' },
  { label: 'Spain', icon: 'i-lucide-map-pin', value: 'ES' },
  { label: 'Netherlands', icon: 'i-lucide-map-pin', value: 'NL' },
  { label: 'Poland', icon: 'i-lucide-map-pin', value: 'PL' }
]

const value = ref<ListboxItem>(items[2]!)
</script>

<template>
  <UListbox
    v-model="value"
    :items="items"
    class="w-full"
  />
</template>

Control términos de búsqueda

Utilice la directiva v-model:search-term para controlar el término de búsqueda.

France
<script setup lang="ts">
const searchTerm = ref('F')
const items = ref([
  { label: 'France', icon: 'i-lucide-map-pin', value: 'FR' },
  { label: 'Germany', icon: 'i-lucide-map-pin', value: 'DE' },
  { label: 'Italy', icon: 'i-lucide-map-pin', value: 'IT' },
  { label: 'Spain', icon: 'i-lucide-map-pin', value: 'ES' },
  { label: 'Netherlands', icon: 'i-lucide-map-pin', value: 'NL' },
  { label: 'Poland', icon: 'i-lucide-map-pin', value: 'PL' }
])
const value = ref()
</script>

<template>
  <UListbox v-model="value" v-model:search-term="searchTerm" filter :items="items" class="w-full" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const searchTerm = ref('F')
const items = ref([
  { label: 'France', icon: 'i-lucide-map-pin', value: 'FR' },
  { label: 'Germany', icon: 'i-lucide-map-pin', value: 'DE' },
  { label: 'Italy', icon: 'i-lucide-map-pin', value: 'IT' },
  { label: 'Spain', icon: 'i-lucide-map-pin', value: 'ES' },
  { label: 'Netherlands', icon: 'i-lucide-map-pin', value: 'NL' },
  { label: 'Poland', icon: 'i-lucide-map-pin', value: 'PL' }
])
const value = ref()
</script>

<template>
  <UListbox v-model="value" v-model:search-term="searchTerm" filter :items="items" class="w-full" />
</template>

Con filtro ignorar

Configure el prop ignore-filter en true para desactivar la búsqueda interna y utilizar su propia lógica de búsqueda.

No data
<script setup lang="ts">
import { refDebounced } from '@vueuse/core'

const searchTerm = ref('')
const searchTermDebounced = refDebounced(searchTerm, 200)

const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'listbox-users-search',
  params: { q: searchTermDebounced },
  transform: (data: { id: number, name: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      value: String(user.id),
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
    }))
  },
  immediate: false
})

onMounted(() => {
  execute()
})
</script>

<template>
  <UListbox
    v-model:search-term="searchTerm"
    :items="users || []"
    :filter="{
      icon: 'i-lucide-search',
      loading: status === 'pending'
    }"
    ignore-filter
    class="w-full"
  />
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { refDebounced } from '@vueuse/core'

const searchTerm = ref('')
const searchTermDebounced = refDebounced(searchTerm, 200)

const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'listbox-users-search',
  params: { q: searchTermDebounced },
  transform: (data: { id: number, name: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      value: String(user.id),
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
    }))
  },
  immediate: false
})

onMounted(() => {
  execute()
})
</script>

<template>
  <UListbox
    v-model:search-term="searchTerm"
    :items="users || []"
    :filter="{
      icon: 'i-lucide-search',
      loading: status === 'pending'
    }"
    ignore-filter
    class="w-full"
  />
</template>
Este ejemplo utiliza refDebounced para refutar las llamadas a la API.

Con campos de filtro

Utilice el prop filter-fields con una matriz de campos para filtrar.

No data
<script setup lang="ts">
const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'typicode-users-email',
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      email: user.email,
      value: String(user.id),
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
    }))
  },
  immediate: false
})

onMounted(() => {
  execute()
})
</script>

<template>
  <UListbox
    :items="users || []"
    :loading="status === 'pending'"
    :filter-fields="['label', 'email']"
    filter
    class="w-full"
  >
    <template #item-label="{ item }">
      {{ item.label }}

      <span class="text-muted">
        {{ item.email }}
      </span>
    </template>
  </UListbox>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'

const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'typicode-users-email',
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      email: user.email,
      value: String(user.id),
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const }
    }))
  },
  immediate: false
})

onMounted(() => {
  execute()
})
</script>

<template>
  <UListbox
    :items="users || []"
    :loading="status === 'pending'"
    :filter-fields="['label', 'email']"
    filter
    class="w-full"
  >
    <template #item-label="{ item }">
      {{ item.label }}

      <span class="text-muted">
        {{ item.email }}
      </span>
    </template>
  </UListbox>
</template>

Con virtualización

Utilice el prop virtualize para habilitar la virtualización de listas grandes como un booleano o un objeto con opciones como { estimateSize: 32, overscan: 12 }.

<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items: ListboxItem[] = Array.from({ length: 1000 }, (_, i) => ({
  label: `Item ${i + 1}`,
  icon: 'i-lucide-file',
  value: i + 1
}))

const value = ref<ListboxItem[]>([])
</script>

<template>
  <UListbox
    v-model="value"
    :items="items"
    multiple
    virtualize
    class="w-full"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items: ListboxItem[] = Array.from({ length: 1000 }, (_, i) => ({
  label: `Item ${i + 1}`,
  icon: 'i-lucide-file',
  value: i + 1
}))

const value = ref<ListboxItem[]>([])
</script>

<template>
  <UListbox
    v-model="value"
    :items="items"
    multiple
    virtualize
    class="w-full"
  />
</template>

As una lista de transferencias

Puede componer dos componentes de Listbox con los controles Button para crear un patrón de lista de transferencia.

Available
France
Germany
Italy
Spain
Netherlands
Poland
Belgium
Portugal
Selected
No data
<script setup lang="ts">
import type { ListboxItem } from '@nuxt/ui'

const items: ListboxItem[] = [
  { label: 'France', icon: 'i-lucide-map-pin', value: 'FR' },
  { label: 'Germany', icon: 'i-lucide-map-pin', value: 'DE' },
  { label: 'Italy', icon: 'i-lucide-map-pin', value: 'IT' },
  { label: 'Spain', icon: 'i-lucide-map-pin', value: 'ES' },
  { label: 'Netherlands', icon: 'i-lucide-map-pin', value: 'NL' },
  { label: 'Poland', icon: 'i-lucide-map-pin', value: 'PL' },
  { label: 'Belgium', icon: 'i-lucide-map-pin', value: 'BE' },
  { label: 'Portugal', icon: 'i-lucide-map-pin', value: 'PT' }
]

const targetItems = ref<ListboxItem[]>([])
const sourceSelection = ref<ListboxItem[]>([])
const targetSelection = ref<ListboxItem[]>([])

const sourceItems = computed(() => items.filter(item => !targetItems.value.some(t => t.value === item.value)))

function transferSelected() {
  targetItems.value = [...targetItems.value, ...sourceSelection.value]
  sourceSelection.value = []
}

function removeSelected() {
  targetItems.value = targetItems.value.filter(item => !targetSelection.value.some(t => t.value === item.value))
  targetSelection.value = []
}
</script>

<template>
  <div class="flex items-stretch gap-4 w-full">
    <div class="flex flex-col flex-1 gap-1">
      <span class="text-sm font-medium text-highlighted">Available</span>

      <UListbox
        v-model="sourceSelection"
        :items="sourceItems"
        multiple
        filter
        class="size-full"
      />
    </div>

    <div class="flex flex-col items-center justify-center gap-1">
      <UButton
        icon="i-lucide-chevron-right"
        color="neutral"
        variant="outline"
        :disabled="!sourceSelection.length"
        @click="transferSelected"
      />
      <UButton
        icon="i-lucide-chevron-left"
        color="neutral"
        variant="outline"
        :disabled="!targetSelection.length"
        @click="removeSelected"
      />
    </div>

    <div class="flex flex-col flex-1 gap-1">
      <span class="text-sm font-medium text-highlighted">Selected</span>

      <UListbox
        v-model="targetSelection"
        :items="targetItems"
        multiple
        filter
        class="size-full"
      />
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { ListboxItem } from '@nuxt/ui'

const items: ListboxItem[] = [
  { label: 'France', icon: 'i-lucide-map-pin', value: 'FR' },
  { label: 'Germany', icon: 'i-lucide-map-pin', value: 'DE' },
  { label: 'Italy', icon: 'i-lucide-map-pin', value: 'IT' },
  { label: 'Spain', icon: 'i-lucide-map-pin', value: 'ES' },
  { label: 'Netherlands', icon: 'i-lucide-map-pin', value: 'NL' },
  { label: 'Poland', icon: 'i-lucide-map-pin', value: 'PL' },
  { label: 'Belgium', icon: 'i-lucide-map-pin', value: 'BE' },
  { label: 'Portugal', icon: 'i-lucide-map-pin', value: 'PT' }
]

const targetItems = ref<ListboxItem[]>([])
const sourceSelection = ref<ListboxItem[]>([])
const targetSelection = ref<ListboxItem[]>([])

const sourceItems = computed(() => items.filter(item => !targetItems.value.some(t => t.value === item.value)))

function transferSelected() {
  targetItems.value = [...targetItems.value, ...sourceSelection.value]
  sourceSelection.value = []
}

function removeSelected() {
  targetItems.value = targetItems.value.filter(item => !targetSelection.value.some(t => t.value === item.value))
  targetSelection.value = []
}
</script>

<template>
  <div class="flex items-stretch gap-4 w-full">
    <div class="flex flex-col flex-1 gap-1">
      <span class="text-sm font-medium text-highlighted">Available</span>

      <UListbox
        v-model="sourceSelection"
        :items="sourceItems"
        multiple
        filter
        class="size-full"
      />
    </div>

    <div class="flex flex-col items-center justify-center gap-1">
      <UButton
        icon="i-lucide-chevron-right"
        color="neutral"
        variant="outline"
        :disabled="!sourceSelection.length"
        @click="transferSelected"
      />
      <UButton
        icon="i-lucide-chevron-left"
        color="neutral"
        variant="outline"
        :disabled="!targetSelection.length"
        @click="removeSelected"
      />
    </div>

    <div class="flex flex-col flex-1 gap-1">
      <span class="text-sm font-medium text-highlighted">Selected</span>

      <UListbox
        v-model="targetSelection"
        :items="targetItems"
        multiple
        filter
        class="size-full"
      />
    </div>
  </div>
</template>

API (Edición española)

Props (accesorios)

Prop Default Type
as
'div'
any

The element or component this component should render as.

id
string
color
'primary'
"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
size
'md'
"sm" | "md" | "xs" | "lg" | "xl"
items
T

The items to display in the list.

modelValue
_Number<_Optional<_Nullable<GetModelValue<T, VK, M, undefined>, Mod>, Mod>, Mod>

The controlled value of the Listbox. Can be bound with v-model.

modelModifiers
Mod
defaultValue
_Number<_Optional<_Nullable<GetModelValue<T, VK, M, undefined>, Mod>, Mod>, Mod>

The default value when not controlled.

multiple
false
M

Whether multiple items can be selected.

valueKey
undefined
VK

When items is an array of objects, select the field to use as the value instead of the object itself.

labelKey
'label'
keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>

The key used to get the label from the item.

descriptionKey
'description'
keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>

The key used to get the description from the item.

loading
boolean

Whether the list is in a loading state.

loadingIcon
appConfig.ui.icons.loading
any

The icon displayed when loading.

filter
false
boolean | Omit<InputProps<AcceptableValue, ModelModifiers>, "modelValue" | "defaultValue">

Whether to display a filter input or not. Can be an object to pass additional props to the input. { placeholder: 'Search...', variant: 'none' }

filterFields
[labelKey]
string[]

The fields to filter by.

ignoreFilter
false
boolean

When true, disable the default filters, useful for custom filtering (useAsyncData, useFetch, etc.).

selectedIcon
appConfig.ui.icons.check
any

The icon displayed when an item is selected.

virtualize
false
boolean | { overscan?: number ; estimateSize?: number | ((index: number) => number) | undefined; } | undefined

Enable virtualization for large lists.

highlight
boolean

Highlight the ring color like a focus state.

autofocus
boolean
autofocusDelay
0
number
by
string | (a: AcceptableValue, b: AcceptableValue): boolean

Use this to compare objects by a particular field, or pass your own comparison function for complete control over how objects are compared.

disabled
boolean

When true, prevents the user from interacting with listbox

highlightOnHover
true
boolean

When true, hover over item will trigger highlight

name
string

The name of the field. Submitted with its owning form as part of a name/value pair.

orientation
"vertical" | "horizontal"

The orientation of the listbox.
Mainly so arrow navigation is done accordingly (left & right vs. up & down)

required
boolean

When true, indicates that the user must set the value before the owning form can be submitted.

selectionBehavior
'toggle'
"replace" | "toggle"

How multiple selection should behave in the collection.

searchTerm
''
string
ui
{ root?: SlotClass; input?: SlotClass; content?: SlotClass; group?: SlotClass; label?: SlotClass; separator?: SlotClass; empty?: SlotClass; loading?: SlotClass; loadingIcon?: SlotClass; item?: SlotClass; itemLeadingIcon?: SlotClass; itemLeadingAvatar?: SlotClass; itemLeadingAvatarSize?: SlotClass; itemLeadingChip?: SlotClass; itemLeadingChipSize?: SlotClass; itemWrapper?: SlotClass; itemLabel?: SlotClass; itemDescription?: SlotClass; itemTrailing?: SlotClass; itemTrailingIcon?: SlotClass; }

Slots

Slot Type
loading
{}
empty
{ searchTerm: string; }
item
{ item: NestedItem<T>; index: number; ui: object; }
item-leading
{ item: NestedItem<T>; index: number; ui: object; }
item-label
{ item: NestedItem<T>; index: number; }
item-description
{ item: NestedItem<T>; index: number; }
item-trailing
{ item: NestedItem<T>; index: number; ui: object; }

Emisiones

Event Type
entryFocus
[event: CustomEvent<any>]
highlight
[payload: { ref: HTMLElement; value: AcceptableValue; } | undefined]
leave
[event: Event]
change
[event: Event]
update:modelValue
[value: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, undefined>, Mod>, Mod>, Mod>]
update:searchTerm
[value: string]

Temas

app.config.ts
export default defineAppConfig({
  ui: {
    listbox: {
      slots: {
        root: 'flex flex-col min-h-0 min-w-0 ring ring-inset ring-default rounded-lg overflow-hidden',
        input: 'border-b border-default',
        content: 'relative overflow-y-auto flex-1 max-h-60 scroll-py-1 focus:outline-none',
        group: 'p-1 isolate',
        label: 'font-semibold text-highlighted',
        separator: '-mx-1 my-1 h-px bg-border',
        empty: 'text-center text-muted',
        loading: 'flex items-center justify-center text-muted',
        loadingIcon: 'animate-spin shrink-0',
        item: [
          'group relative w-full flex items-start select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
          'transition-colors before:transition-colors'
        ],
        itemLeadingIcon: [
          'shrink-0 text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
          'transition-colors'
        ],
        itemLeadingAvatar: 'shrink-0',
        itemLeadingAvatarSize: '',
        itemLeadingChip: 'shrink-0',
        itemLeadingChipSize: '',
        itemWrapper: 'flex-1 flex flex-col min-w-0',
        itemLabel: 'truncate',
        itemDescription: 'truncate text-muted',
        itemTrailing: 'ms-auto inline-flex gap-1.5 items-center',
        itemTrailingIcon: 'shrink-0'
      },
      variants: {
        size: {
          xs: {
            label: 'p-1 text-[10px]/3 gap-1',
            empty: 'py-3 text-xs',
            loading: 'py-3',
            loadingIcon: 'size-4',
            item: 'p-1 text-xs gap-1',
            itemLeadingIcon: 'size-4',
            itemLeadingAvatarSize: '3xs',
            itemLeadingChip: 'size-4',
            itemLeadingChipSize: 'sm',
            itemTrailingIcon: 'size-4'
          },
          sm: {
            label: 'p-1.5 text-[10px]/3 gap-1.5',
            empty: 'py-4 text-xs',
            loading: 'py-4',
            loadingIcon: 'size-4',
            item: 'p-1.5 text-xs gap-1.5',
            itemLeadingIcon: 'size-4',
            itemLeadingAvatarSize: '3xs',
            itemLeadingChip: 'size-4',
            itemLeadingChipSize: 'sm',
            itemTrailingIcon: 'size-4'
          },
          md: {
            label: 'p-1.5 text-xs gap-1.5',
            empty: 'py-6 text-sm',
            loading: 'py-6',
            loadingIcon: 'size-5',
            item: 'p-1.5 text-sm gap-1.5',
            itemLeadingIcon: 'size-5',
            itemLeadingAvatarSize: '2xs',
            itemLeadingChip: 'size-5',
            itemLeadingChipSize: 'md',
            itemTrailingIcon: 'size-5'
          },
          lg: {
            label: 'p-2 text-xs gap-2',
            empty: 'py-7 text-sm',
            loading: 'py-7',
            loadingIcon: 'size-5',
            item: 'p-2 text-sm gap-2',
            itemLeadingIcon: 'size-5',
            itemLeadingAvatarSize: '2xs',
            itemLeadingChip: 'size-5',
            itemLeadingChipSize: 'md',
            itemTrailingIcon: 'size-5'
          },
          xl: {
            label: 'p-2 text-sm gap-2',
            empty: 'py-8 text-base',
            loading: 'py-8',
            loadingIcon: 'size-6',
            item: 'p-2 text-base gap-2',
            itemLeadingIcon: 'size-6',
            itemLeadingAvatarSize: 'xs',
            itemLeadingChip: 'size-6',
            itemLeadingChipSize: 'lg',
            itemTrailingIcon: 'size-6',
            itemDescription: 'text-sm'
          }
        },
        color: {
          primary: {
            root: 'outline-primary/25 has-focus-visible:outline-3 has-focus-visible:ring-primary'
          },
          secondary: {
            root: 'outline-secondary/25 has-focus-visible:outline-3 has-focus-visible:ring-secondary'
          },
          success: {
            root: 'outline-success/25 has-focus-visible:outline-3 has-focus-visible:ring-success'
          },
          info: {
            root: 'outline-info/25 has-focus-visible:outline-3 has-focus-visible:ring-info'
          },
          warning: {
            root: 'outline-warning/25 has-focus-visible:outline-3 has-focus-visible:ring-warning'
          },
          error: {
            root: 'outline-error/25 has-focus-visible:outline-3 has-focus-visible:ring-error'
          },
          neutral: {
            root: 'outline-inverted/25 has-focus-visible:outline-3 has-focus-visible:ring-inverted'
          }
        },
        virtualize: {
          true: {
            content: 'p-1 isolate'
          },
          false: {
            content: 'divide-y divide-default'
          }
        },
        disabled: {
          true: {
            root: 'opacity-75 cursor-not-allowed'
          }
        },
        highlight: {
          true: ''
        }
      },
      compoundVariants: [
        {
          color: 'primary',
          highlight: true,
          class: {
            root: 'ring ring-inset ring-primary'
          }
        },
        {
          color: 'neutral',
          highlight: true,
          class: {
            root: 'ring ring-inset ring-inverted'
          }
        }
      ],
      defaultVariants: {
        color: 'primary',
        size: 'md'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        listbox: {
          slots: {
            root: 'flex flex-col min-h-0 min-w-0 ring ring-inset ring-default rounded-lg overflow-hidden',
            input: 'border-b border-default',
            content: 'relative overflow-y-auto flex-1 max-h-60 scroll-py-1 focus:outline-none',
            group: 'p-1 isolate',
            label: 'font-semibold text-highlighted',
            separator: '-mx-1 my-1 h-px bg-border',
            empty: 'text-center text-muted',
            loading: 'flex items-center justify-center text-muted',
            loadingIcon: 'animate-spin shrink-0',
            item: [
              'group relative w-full flex items-start select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
              'transition-colors before:transition-colors'
            ],
            itemLeadingIcon: [
              'shrink-0 text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
              'transition-colors'
            ],
            itemLeadingAvatar: 'shrink-0',
            itemLeadingAvatarSize: '',
            itemLeadingChip: 'shrink-0',
            itemLeadingChipSize: '',
            itemWrapper: 'flex-1 flex flex-col min-w-0',
            itemLabel: 'truncate',
            itemDescription: 'truncate text-muted',
            itemTrailing: 'ms-auto inline-flex gap-1.5 items-center',
            itemTrailingIcon: 'shrink-0'
          },
          variants: {
            size: {
              xs: {
                label: 'p-1 text-[10px]/3 gap-1',
                empty: 'py-3 text-xs',
                loading: 'py-3',
                loadingIcon: 'size-4',
                item: 'p-1 text-xs gap-1',
                itemLeadingIcon: 'size-4',
                itemLeadingAvatarSize: '3xs',
                itemLeadingChip: 'size-4',
                itemLeadingChipSize: 'sm',
                itemTrailingIcon: 'size-4'
              },
              sm: {
                label: 'p-1.5 text-[10px]/3 gap-1.5',
                empty: 'py-4 text-xs',
                loading: 'py-4',
                loadingIcon: 'size-4',
                item: 'p-1.5 text-xs gap-1.5',
                itemLeadingIcon: 'size-4',
                itemLeadingAvatarSize: '3xs',
                itemLeadingChip: 'size-4',
                itemLeadingChipSize: 'sm',
                itemTrailingIcon: 'size-4'
              },
              md: {
                label: 'p-1.5 text-xs gap-1.5',
                empty: 'py-6 text-sm',
                loading: 'py-6',
                loadingIcon: 'size-5',
                item: 'p-1.5 text-sm gap-1.5',
                itemLeadingIcon: 'size-5',
                itemLeadingAvatarSize: '2xs',
                itemLeadingChip: 'size-5',
                itemLeadingChipSize: 'md',
                itemTrailingIcon: 'size-5'
              },
              lg: {
                label: 'p-2 text-xs gap-2',
                empty: 'py-7 text-sm',
                loading: 'py-7',
                loadingIcon: 'size-5',
                item: 'p-2 text-sm gap-2',
                itemLeadingIcon: 'size-5',
                itemLeadingAvatarSize: '2xs',
                itemLeadingChip: 'size-5',
                itemLeadingChipSize: 'md',
                itemTrailingIcon: 'size-5'
              },
              xl: {
                label: 'p-2 text-sm gap-2',
                empty: 'py-8 text-base',
                loading: 'py-8',
                loadingIcon: 'size-6',
                item: 'p-2 text-base gap-2',
                itemLeadingIcon: 'size-6',
                itemLeadingAvatarSize: 'xs',
                itemLeadingChip: 'size-6',
                itemLeadingChipSize: 'lg',
                itemTrailingIcon: 'size-6',
                itemDescription: 'text-sm'
              }
            },
            color: {
              primary: {
                root: 'outline-primary/25 has-focus-visible:outline-3 has-focus-visible:ring-primary'
              },
              secondary: {
                root: 'outline-secondary/25 has-focus-visible:outline-3 has-focus-visible:ring-secondary'
              },
              success: {
                root: 'outline-success/25 has-focus-visible:outline-3 has-focus-visible:ring-success'
              },
              info: {
                root: 'outline-info/25 has-focus-visible:outline-3 has-focus-visible:ring-info'
              },
              warning: {
                root: 'outline-warning/25 has-focus-visible:outline-3 has-focus-visible:ring-warning'
              },
              error: {
                root: 'outline-error/25 has-focus-visible:outline-3 has-focus-visible:ring-error'
              },
              neutral: {
                root: 'outline-inverted/25 has-focus-visible:outline-3 has-focus-visible:ring-inverted'
              }
            },
            virtualize: {
              true: {
                content: 'p-1 isolate'
              },
              false: {
                content: 'divide-y divide-default'
              }
            },
            disabled: {
              true: {
                root: 'opacity-75 cursor-not-allowed'
              }
            },
            highlight: {
              true: ''
            }
          },
          compoundVariants: [
            {
              color: 'primary',
              highlight: true,
              class: {
                root: 'ring ring-inset ring-primary'
              }
            },
            {
              color: 'neutral',
              highlight: true,
              class: {
                root: 'ring ring-inset ring-inverted'
              }
            }
          ],
          defaultVariants: {
            color: 'primary',
            size: 'md'
          }
        }
      }
    })
  ]
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitHub.

Changelog (Edición española)

No recent changes