Dropdown — Guidelines
Use the API control (top right) to show guidance for the selected API.
Choosing the options prop
Use when rows are plain { value, label, … } data (static lists, REST/GraphQL, computed filters). Enable filterable for built-in label search, or pre-filter the .options array (.filterLocally="false" for server-side rules). Set hidden: true on objects to hide rows without splicing the array.
Do not add <catnip-dropdown-option> children when using options — they are ignored and a dev warning is logged.
Options prop — recipes
Map API data
type Service = { id: string; name: string; active: boolean };
const services = computed(() =>
apiData.value.map((s) => ({
value: s.id,
label: s.name,
disabled: !s.active
}))
);<catnip-dropdown label="Service" .options="services" .modelValue="id" @update:modelValue="id = $event.detail[0]" />Built-in client filter
Enable filterable. The dropdown filters label text locally (filterLocally defaults to true).
Parent-controlled filter (server or custom rules)
- Own filter state in the parent (
query,@update:filterValue). - Pass a computed
optionsarray (already filtered). - Set
.filterLocally="false"so the dropdown does not filter again.
const query = ref(""); const filtered = computed(() => allServices.value.filter((s) => s.label.includes(query.value)));<catnip-dropdown
filterable
.filterLocally="false"
.options="filtered"
.filterValue="query"
@update:filterValue="query = $event.detail[0]"
…
/>Hide rows without removing them
Set hidden: true on option objects instead of splicing the array when toggling visibility client-side.
Multi-select display
| displayMode | Trigger shows |
|---|---|
value | Comma-separated labels (default) |
chips | Removable catnip-chip chips |
count | "{n} selected" (override with selectedCountLabel) |
Works with both options and child-element APIs.
Validation
Set intent="danger" and supportingText together — same pattern as Input. The dropdown does not mirror native :invalid automatically.
Migration from EndUi (options prop)
| EndUi | Catnip |
|---|---|
options + keyField / valueField | .options prop — map to { value, label } |
allowMultiple | multiple |
useChip | display-mode="chips" |
hasSearch | filterable or list-header slot |
error / hint | intent + supportingText |
Accessibility
- Tab to the trigger; when the panel is closed, Enter, Space, or ArrowDown opens it (ArrowUp does not open from a closed trigger).
- With
filterable, focus moves to the search field on open; you can type spaces in the filter. ArrowUp/Down, Home/End, Enter, and Escape in the filter move keyboard focus in the list; ordinary letters stay in the filter input. - When the panel is open and focus is on the trigger (non-filterable), ArrowUp/Down, Home/End, typeahead, Enter/Space navigate and select.
- On open, the first selected visible option is highlighted when possible.
- Escape closes; focus returns to the trigger (or the first focusable child in a custom
triggerslot).