# Searchable Term/Authority Picker — Design **Date:** 2026-06-06 **Status:** Approved (brainstorming) — ready for implementation planning. **Issue:** #27. ## Context The object authoring form renders **term** and **authority** flexible fields as native ``). ## Error handling / edges - **Options still loading** (`useTerms`/`useAuthorities` pending): the combobox shows the placeholder and is effectively empty/disabled until options arrive — same as the current ``, which also can't render a missing option. - **Empty vocabulary**: the combobox shows the placeholder and an empty list. ## Testing - **`web/src/objects/field-input.test.tsx`** (update): drive the combobox instead of the native select — open it, type to filter, assert only matching options show, select one and assert the rhf value is the option **id**; clear and assert `""`. The popup renders in a **portal**, so query it via `within(document.body)` (the established pattern from the dialog work). Keep the existing non-term/authority field-type tests (text/integer/date/ boolean/localized_text) untouched. - **Storybook** (`web/src/objects/field-input.stories.tsx` or a focused `combobox.stories.tsx`): stories for the combobox — default/placeholder, filter-as-you-type, a selected value. Mirror the established story format (`@storybook/react-vite`, `storybook/test`, `tags: ['ai-generated']`, single quotes). (Per the standing rule: stories for meaningful interactive components.) - **Bundle:** `pnpm check:size` — the **index** chunk stays ≤ 150 KB gz (combobox weight is in the lazy object-form chunk; confirm the index didn't grow materially). ## Acceptance criteria 1. Term and authority fields render a **searchable combobox** that filters the loaded options by active-locale label as you type; selecting commits the term/authority **id** (value contract unchanged); the field is clearable when not required. 2. Built on **Base UI's `combobox`** primitive via a `ui/combobox.tsx` wrapper — no new npm dependency. 3. `useTerms`/`useAuthorities` unchanged (client-side filtering; no backend change). 4. `field-input.test.tsx` covers open/filter/select/clear; a Storybook story exists; other field types unchanged. 5. `pnpm typecheck` + `pnpm lint` (no `any`/`eslint-disable`/`@ts-ignore`) + `pnpm test` + `pnpm build` green; index bundle ≤ 150 KB gz; en/sv parity for any new i18n keys; no codename. ## Out of scope → follow-up issue - **Server-side term/authority search** (`GET /api/admin/vocabularies/{id}/terms?q=`, `authorities?q=`, debounced, top-N) for genuinely large vocabularies, **and** resolving a selected id→label when the item isn't in the filtered/loaded set (needs a by-id lookup). File this as a new issue when a vocabulary actually grows large. - Multi-select term/authority fields (the schema is single-value today).