Listbox

Une liste sélectionnable d'éléments avec recherche, virtualisation et rendu d'éléments enrichi.

Utilisation

Utilisez la directive v-model pour contrôler la valeur de la boîte de liste ou la prop default-value pour définir la valeur initiale lorsque vous n'avez pas besoin de contrôler son état.

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>

Éléments

Utilisez le prop items comme un tableau d'objets avec les propriétés suivantes:

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>

Vous pouvez également passer un tableau de tableaux au prop items pour afficher des groupes d'éléments séparés.

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>

multiple

Utilisez la prop multiple pour permettre de sélectionner plusieurs éléments. Lorsqu 'elle est activée, la v-model sera un tableau.

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>

Clé ### Value

Vous pouvez choisir de lier une propriété unique de l'objet plutôt que l'objet entier en utilisant 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>

Filtre

Utilisez la prop filter pour afficher une entrée de filtre ou passer un objet pour personnaliser le composant 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>

Selected Icône

Utilisez la prop selected-icon pour personnaliser l'icône lorsqu 'un élément est sélectionné. Par défaut i-lucide-check.

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>

Size

Utilisez la prop size pour modifier la taille de la boîte de liste.

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>

Chargement

Utilisez la prop loading pour afficher un indicateur de chargement. Utilisez la prop loading-icon pour personnaliser l'icône.

<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>

Disabled

Utilisez la prop disabled pour empêcher toute interaction de l'utilisateur avec la boîte de liste.

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>

Exemples

Avec type d'éléments

Vous pouvez utiliser la propriété type avec separator pour afficher un séparateur entre les éléments ou label pour afficher une étiquette.

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>
Lorsque vous utilisez des éléments label comme en-têtes de groupe, passez un tableau de tableaux afin qu 'une étiquette soit filtrée avec son groupe lors de la recherche.

With icône dans les éléments

Vous pouvez utiliser la propriété icon pour afficher un Icon à l'intérieur des éléments.

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>

Avec avatar dans les éléments

Vous pouvez utiliser la propriété avatar pour afficher un Avatar à l'intérieur des éléments.

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>

Avec puce dans les articles

Vous pouvez utiliser la propriété chip pour afficher un Chip à l'intérieur des éléments.

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>

Avec la description dans les articles

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 élément sélectionné (s)

Vous pouvez contrôler l'élément sélectionné à l'aide de la prop default-value ou de la directive 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 terme de recherche

Utilisez la directive v-model:search-term pour contrôler le terme de recherche.

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>

With ignore le filtre

Réglez la prop ignore-filter sur true pour désactiver la recherche interne et utiliser votre propre logique de recherche.

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>
Cet exemple utilise refDebounced pour déboulonner les appels d'API.

With filter fields

Utilisez le prop filter-fields avec un tableau de champs pour filtrer.

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>

Avec virtualisation

Utilisez la prop virtualize pour activer la virtualisation de grandes listes en tant que booléen ou objet avec des options telles que { 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 une liste de transfert

Vous pouvez composer deux composants Listbox avec des contrôles Button pour créer un modèle de liste de transfert.

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 is

Props and

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; }

Emits

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]

Thème

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 écrit

No recent changes