Listbox

A list of options that can be selected by the user.

	<script lang="ts">
  import { Listbox } from "bits-ui";
  import Check from "phosphor-svelte/lib/Check";
  import Palette from "phosphor-svelte/lib/Palette";
  import CaretUpDown from "phosphor-svelte/lib/CaretUpDown";
  import CaretDoubleUp from "phosphor-svelte/lib/CaretDoubleUp";
  import CaretDoubleDown from "phosphor-svelte/lib/CaretDoubleDown";
 
  const themes = [
    { value: "light-monochrome", label: "Light Monochrome" },
    { value: "dark-green", label: "Dark Green" },
    { value: "svelte-orange", label: "Svelte Orange" },
    { value: "punk-pink", label: "Punk Pink" },
    { value: "ocean-blue", label: "Ocean Blue" },
    { value: "sunset-red", label: "Sunset Red" },
    { value: "forest-green", label: "Forest Green" },
    { value: "lavender-purple", label: "Lavender Purple" },
    { value: "mustard-yellow", label: "Mustard Yellow" },
    { value: "slate-gray", label: "Slate Gray" },
    { value: "neon-green", label: "Neon Green" },
    { value: "coral-reef", label: "Coral Reef" },
    { value: "midnight-blue", label: "Midnight Blue" },
    { value: "crimson-red", label: "Crimson Red" },
    { value: "mint-green", label: "Mint Green" },
    { value: "pastel-pink", label: "Pastel Pink" },
    { value: "golden-yellow", label: "Golden Yellow" },
    { value: "deep-purple", label: "Deep Purple" },
    { value: "turquoise-blue", label: "Turquoise Blue" },
    { value: "burnt-orange", label: "Burnt Orange" }
  ];
 
  let value = $state<string>("");
  const selectedLabel = $derived(
    value
      ? themes.find((theme) => theme.value === value)?.label
      : "Select a theme"
  );
</script>
 
<Listbox.Root type="single" bind:value>
  <Listbox.Trigger
    class="inline-flex h-input w-[296px] select-none items-center rounded-9px border border-border-input bg-background px-[11px] text-sm transition-colors placeholder:text-foreground-alt/50"
    aria-label="Select a theme"
  >
    <Palette class="mr-[9px] size-6 text-muted-foreground" />
    {selectedLabel}
    <CaretUpDown class="ml-auto size-6 text-muted-foreground" />
  </Listbox.Trigger>
  <Listbox.Portal>
    <Listbox.Content
      class="max-h-96 w-[var(--bits-listbox-trigger-width)] min-w-[var(--bits-listbox-trigger-width)] rounded-xl border border-muted bg-background px-1 py-3 shadow-popover outline-none"
      sideOffset={10}
    >
      <Listbox.ScrollUpButton class="flex w-full items-center justify-center">
        <CaretDoubleUp class="size-3" />
      </Listbox.ScrollUpButton>
      <Listbox.Viewport class="p-1">
        {#each themes as theme, i (i + theme.value)}
          <Listbox.Item
            class="flex h-10 w-full select-none items-center rounded-button py-3 pl-5 pr-1.5 text-sm capitalize outline-none duration-75 data-[highlighted]:bg-muted"
            value={theme.value}
            label={theme.label}
          >
            {#snippet children({ selected })}
              {theme.label}
              {#if selected}
                <div class="ml-auto">
                  <Check />
                </div>
              {/if}
            {/snippet}
          </Listbox.Item>
        {/each}
      </Listbox.Viewport>
      <Listbox.ScrollDownButton class="flex w-full items-center justify-center">
        <CaretDoubleDown class="size-3" />
      </Listbox.ScrollDownButton>
    </Listbox.Content>
  </Listbox.Portal>
</Listbox.Root>

Structure

	<script lang="ts">
	import { Listbox } from "bits-ui";
</script>
 
<Listbox.Root>
	<Listbox.Label />
	<Listbox.Content>
		<Listbox.Group>
			<Listbox.GroupLabel />
			<Listbox.Item />
		</Listbox.Group>
	</Listbox.Content>
</Listbox.Root>