Select
Two field types, not six (AD decision, 2 Sep 2026 — review ACRM-76–81, pick ACRM-105). The four approved dropdown types A–D (Petr, 21 Aug 2026 — docs/PLAN-dropdown-sjednoceni.md in acrm) are two axes — search yes/no × multiple yes/no — so the family has Select (closed list) and Record select (searchable list of records), each with a multiple mode, plus Nav select (context switch in the top bar, different trigger) and Picker menu (action menu, not a field).
Everything else that used to be its own entry is a mode or a usage of those two and is now deprecated: MultiSelect = Select with multiple (1 usage), Combobox = Record select with free text (1 usage), CheckMenu = the multiple mode drawn as a menu (2), RailPickerMenu = Record select anchored in a rail row (2), EntityPicker = Record select with async search (12), ProductPicker = the same limited to products (2). They stay listed until their usages are migrated; nothing new is built on them. Rule that binds the family (docs/DS-USAGE.md): dropdowns are always the DS popover, never a native <select>.
Values measured from apps/web/src/ds.css and apps/web/src/ds/inputs.css on main: shell .acrm-popover (or .acrm-recordselect-pop for search panels) = --surface-100, 1px --border-strong, --radius-md, --shadow-pop, padding --sp-2, z-index 101 over a scrim at 85; row = 500 13px/20px var(--font-sans), padding --sp-2 --sp-3 → 32px, hover --hover-surface; select-one check = .chk in --accent, hidden with visibility; multi = .acrm-checkbox 16px, 1.5px --border-strong, --radius-xs, on the RIGHT; search row = borderless input 400 14px, 18px icon, hairline --border below; list scrolls inside max-height: 264px. Field triggers (.acrm-select-trigger, .acrm-recordselect-trigger, .acrm-combobox) are 32px, --radius-sm, open state = --accent border + 3px accent halo (16%). Top-bar trigger .tchip = --control-h 30px, --radius-md, --shadow-xs, open = --active-surface.
Which field for which need
| Need | Use | Not |
|---|---|---|
| One value from a closed list (≈10 options or fewer) | Select — <Select> / .acrm-select-trigger | native <select>, a radio group with 10+ options |
| Several values from a closed list | Select with multiple (checkbox on the right, menu stays open) | MultiSelect, a bespoke checkbox menu, several selects |
| More than ~10 items, or records (people, companies, products), single or multiple | Record select — <RecordSelect> (search row, list ≤ 264px) | Select with a long list, an ad-hoc dropdown |
| Free text with suggestions (address, ARES) | Record select with free text allowed | Combobox, <datalist> |
| Search that hits the server as you type | Record select (async) | EntityPicker, ProductPicker |
| Picking a value inside a record rail | Record select anchored to the rail value | RailPickerMenu |
| Switching context in the top bar (pipeline, entity) | Nav select — <NavSelect> / .tchip | Select in the bar, a heading that opens a menu on its own |
| A menu of actions (not a value) | Picker menu — <PickerMenu> / .acrm-popover | Select, a kebab that renders its own menu |
Dropdown types
| Type | Anatomy | Package primitive | App pickers on it |
|---|---|---|---|
| A · plain menu | rows with optional 18px icon or stage dot, one line (ellipsis), accent check on the selected row, no trailing tag; closes on pick | PickerMenu, NavSelect, Select | RecordActionsMenu, ContextVariablesMenu, AccountingEntityPicker, TemplateMenu (under 10 templates) |
| B · search | sticky search row + list ≤ 264px + empty text; single value, check on the right | RecordSelect (single), Combobox (free text) | RailPickerMenu single (OwnerPickerEditor), TemplateMenu, DialCodePicker, RecordSearchSelect, AssignPicker, ProductPicker |
| C · multiselect | rows with the DS checkbox on the right; the menu stays open on toggle; optional reorder by drag | MultiSelect | CheckMenu (LayoutMenu, CategoryFilterChip), FilterBar |
| D · search + multi | B + C, selection pinned on top, hairline between groups, optional footer | RecordSelect multi | RailPickerMenu multi (TagsEditor), EntityPicker |
The story Components / Select → Dropdown types shows the four side by side.
Where each picker sits
| Picker | Type | Primitive it uses | Verdict |
|---|---|---|---|
Select (@acrm/ui) | A | .acrm-select-trigger + Popover + .acrm-popover-item .chk | canon |
MultiSelect (@acrm/ui) | C | .acrm-select-trigger + Popover + .acrm-checkbox right | canon |
Combobox (@acrm/ui) | B (free text) | .acrm-combobox + .acrm-combobox-pop via useAnchoredMenu | canon |
RecordSelect (@acrm/ui) | B / D | .acrm-recordselect-* via useAnchoredMenu | canon — single mode still draws .acrm-checkbox, not the F261 accent check .acrm-recordselect-ck that RailPickerMenu emits; align in the package |
NavSelect (@acrm/ui) | A | .tchip + PickerMenu | canon (composition) |
PickerMenu (@acrm/ui) | A | Popover + .acrm-popover-item | canon |
CheckMenu (components/CheckMenu.tsx, ds/check-menu.css) | C | Popover + .acrm-popover-item[menuitemcheckbox] + .acrm-checkbox right, .cm-reorder / .cm-drop-line | canon type C, app-side — promote to the package when a second consumer outside the app appears |
RailPickerMenu (components/RailPickerMenu.tsx) | B / D | .acrm-recordselect-pop/-search/-list/-opt, .acrm-popover-sep, useAnchoredMenu; anchor .rr-ev.rpk-anchor, footer .rpk-foot (record-rail.css) | canon in the rail (F194/F195) — composition of canonical rows, no own shell |
EntityPicker (components/EntityPicker.tsx) | D | AddRefMenu shell (.acrm-popover.eref-add-pop, useAnchoredPanel) + .acrm-recordselect-search/-list/-opt rows; server typeahead | duplicate shell — rows are canonical, shell and anchoring re-implement Popover/useAnchoredMenu; consolidation candidate (plan MR 15) |
ProductPicker (components/ProductPicker.tsx) | B (+ free-text row) | same as EntityPicker (AddRefMenu + record-select rows), group heading pending AD gate V2 | duplicate shell — consolidation candidate (plan MR 15) |
RecordSearchSelect (components/RecordSearchSelect.tsx) | B | .acrm-recordselect trigger + AddRefMenu + record-select rows; server typeahead | duplicate — exists only because RecordSelect filters in memory; give RecordSelect async options and retire it (plan MR 15) |
AddRefMenu (components/AddRefMenu.tsx) | shell for B/D | createPortal + useAnchoredPanel, .acrm-popover.eref-add-pop | duplicate of Popover + useAnchoredMenu — consolidation candidate |
DialCodePicker (components/multivalue/DialCodePicker.tsx) | B | Popover shell + .acrm-recordselect-search; rows .phe-ccrow (multi-value.css) | partial — shell canonical (plan MR 10), rows bespoke; consolidation candidate |
TemplateMenu (components/mail/compose/TemplateMenu.tsx) | B (A under 10) | Popover + .acrm-recordselect-search + .acrm-popover-item, .acrm-popover-empty | composition — fine (.mc-tplstick keeps the search row sticky) |
LayoutMenu (components/record/LayoutMenu.tsx) | C | CheckMenu with onReorder | composition — fine |
ContextVariablesMenu (pages/settings/ContextVariablesMenu.tsx) | A | Popover + .acrm-popover-item (tag removed 28 Sep 2026) | composition — fine |
AccountingEntityPicker (components/accounting/AccountingEntityPicker.tsx) | A | NavSelect; SectionTopBarChip when there is one entity | composition — fine |
AssignPicker (components/mail/AssignPicker.tsx) | B | bespoke .rcpt-menu / .rcpt-opt (mail.css) via createPortal + useAnchoredPanel | duplicate — consolidation candidate (plan MR 7) |
PlaudPickerDialog (components/meetings/PlaudPickerDialog.tsx) | — | Dialog + ItemList + .acrm-checkbox | not a dropdown; a dialog list — fine, outside the family |
OwnerPickerEditor (components/record/OwnerPickerEditor.tsx) | B | RailPickerMenu mode="single" | composition — fine |
RecordActionsMenu (components/record/RecordActionsMenu.tsx) | A | Popover + .acrm-popover-item (.danger last) | composition — fine |
TagsEditor (components/TagsEditor.tsx) | D | RailPickerMenu mode="multi" + .rpk-create footer | composition — fine |
ChannelsPopoverEditor (components/multivalue/ChannelsPopoverEditor.tsx) | A (type cell) | native <select class="phe-type"> | native — violation; the only native select left in the app (the ds-ok comment argues the box does not fit the row — the fix is a quiet type A trigger, not a native control) |
Consolidation notes
- One shell:
AddRefMenu+useAnchoredPanel(EntityPicker, ProductPicker, RecordSearchSelect) and.rcpt-menu(AssignPicker) re-implement whatPopoveranduseAnchoredMenualready do. Plan MR 7 and MR 15 fold them into type B. - One row:
DialCodePickerrows (.phe-ccrow) should become.acrm-popover-item(the code in the name, no trailing tag). - One check:
RecordSelectsingle should draw.acrm-recordselect-cklikeRailPickerMenu— a checkbox promises multi-select (F261). - Async options on
RecordSelectremove the reason forRecordSearchSelect. CheckMenuandRailPickerMenuare canonical by anatomy but live app-side; the catalog renders their markup, not the components.- Zero native selects is the target:
ChannelsPopoverEditortype cell is the last one.
Legacy card Inputs — what still holds
Harvested from legacy/Inputs.html ("Výběr & rozbalovací nabídky", "Rozbalovací nabídky") and legacy/popover.html, checked against apps/web/src/ds.css and apps/web/src/ds/inputs.css:
- Still true: "No headings inside menus — never an eyebrow above the items; the only exception is a hairline group separator." "Menu, combobox and popover carry
--shadow-popover a hairline ring and--radius-md." "The active item in a single select carries the check on the right; in a multi select the filled checkbox on the right (D6, 22 Aug 2026)." "Record select opens with a search box on top (hairline), the list scrolls inside 264px; use it whenever the list has more than ~10 items." "The LIST scrolls, not the panel — a scrolling panel with a sticky header produced F257." "One-line items 500 13/20 → 32px;.subdescriptions removed 21 Aug 2026; the trailing.tagremoved 28 Sep 2026 (ACRM-375–377) — a row is its name only." "Fields are flat at rest; the shadow belongs to the open menu." Record select variants "single (check, closes on pick) · text-only (no avatar, code lists) · in menu (no trigger, search is the first row) · search without list (hairline disappears)". - Superseded or ahead of code: the card's Record select "single" check is only implemented app-side (
RailPickerMenu);RecordSelectin the package still draws a checkbox in single mode (F261 alignment pending). The card's "text-only" Record select rows have no package prop —RecordSelectalways renders an avatar; the text-only row exists inRailPickerMenu(avataromitted). The card's "Nadpis-dropdown (s ikonou)" is the.pipe-btnscreen switch (family Section top bar), not a member of this family. The registry summary "native select on mobile" for Select is not in code — the native element is sr-only form backing on every viewport.
Sub-components
Current
- Select · accessibility — closed list, single or
multiple - Record select · accessibility — searchable records, single or multiple, optional free text
- Nav select · accessibility — context switch in the top bar
- Picker menu · accessibility — menu of actions
Deprecated — listed for migration, never for new work
| Deprecated | Replace with | Usages to migrate |
|---|---|---|
| Multi-select | Select with multiple | 1 (PersonRail) |
| Combobox | Record select with free text | 1 (ChartAccountDialogs) |
| Check menu | Select with multiple / Record select multi | 2 |
| Rail picker | Record select anchored in a rail row | 2 |
| Entity picker | Record select with async search | 12 |
| Product picker | Record select, async, products | 2 |
Migration order (largest first): Entity picker → Product picker → Check menu → Rail picker → Multi-select → Combobox. Each step is a separate merge request; the deprecated entry disappears from the registry once its last usage is gone.
Source: docs/select/index.usage.md · GitLab