Supply options as data, load them from a server, and define menu actions.

Select, Combobox, Autocomplete, Listbox, and Trigger Menu accept items as data. Use this when your choices already come from an array. You can also compose their item parts yourself.

Start with Strings

<script lang="ts">
  import {
    Select,
    SelectContent,
    SelectTrigger,
    SelectValue,
  } from "@ui-sdk/svelte/select"
</script>

<Select items={["Apple", "Banana", "Pear"]}>
  <SelectTrigger aria-label="Fruit"
    ><SelectValue placeholder="Choose a fruit" /></SelectTrigger
  >
  <SelectContent />
</Select>

Each string is both the value and its label. Use objects when those need to differ:

const items = [
  { value: "apple", label: "Apple" },
  { value: "banana", label: "Banana", disabled: true },
]

Items can have keywords for searching. Group them with { type: "group", label, items }, or separate them with { type: "separator" }.

For object values, provide itemToValue for the submitted string and itemToLabel for the displayed text. Select and Combobox show complete examples.

Style the Items

Items as data render bare parts, each with just its label. To style them, render the parts yourself from your array, with your classes right on them. Type the array with ListData, so a mistake in it shows up where you write it:

<script lang="ts">
  import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
    type ListData,
  } from "@ui-sdk/svelte/select"

  const fruits = [
    { value: "apple", label: "Apple" },
    { value: "banana", label: "Banana" },
  ] satisfies ListData
</script>

<Select items={fruits}>
  <SelectTrigger aria-label="Fruit" class="…"
    ><SelectValue placeholder="Choose a fruit" /></SelectTrigger
  >
  <SelectContent class="…">
    {#each fruits as fruit (fruit.value)}
      <SelectItem value={fruit.value} class="…">{fruit.label}</SelectItem>
    {/each}
  </SelectContent>
</Select>

A list that searches still filters the items you render, and hides the ones that don't match. When the items come from state, like results from a server, the list part's children snippet gives you the ones to show: {#snippet children(state)} inside a SelectList, then render state.items.

Search and Load Items

Searchable components accept a filter to change how typing narrows their items. Async Options handles server results, debouncing, and stale requests.

Data lists can virtualize large collections. You don't need to render every item yourself.

Describe a Menu

A MenuData array describes actions, separators, groups, and submenus. A plain string is an action whose value and label are the string:

<script lang="ts">
  import { Menu, MenuTrigger, type MenuData } from "@ui-sdk/svelte/menu"

  const actions: MenuData = [
    { value: "open", label: "Open", shortcut: "mod+o" },
    { type: "separator" },
    {
      type: "submenu",
      label: "Share",
      items: [{ value: "email", label: "Email" }],
    },
  ]
</script>

<Menu items={actions} onAction={(value) => console.log(value)}>
  <MenuTrigger>File</MenuTrigger>
</Menu>

A data menu renders bare parts too. To style it, place a MenuContent of your own and render the items in it, as Menu shows. That page also covers checkbox items, radio groups, and nested menus.

Keys and Shortcuts

loop controls whether arrow keys wrap around a list. Components that support orientation use it to choose the navigation axis.

A trigger's shortcut="mod+k" opens it from elsewhere on the page. A data menu runs item shortcuts while closed; a manually rendered MenuItem's shortcut only displays the keys. Shortcuts covers registering your own.