Entity picker

Several references to records of mixed types (user, contact, organization, deal) as removable tokens — the form variant of Entity reference. App component EntityPicker (apps/web/src/components/EntityPicker.tsx): a composition over the canonical Record select, not a select of its own. Picked records render as <EntityRef removable> tokens in .eref-field; the always-present "Přidat" (.add-ref) opens RecordSelect anchored to it in adding mode (keepOpen, value={null}) with server search over /mentions/search.

Status: beta (AD 3 Oct 2026). The former duplicate shell (AddRefMenu) is gone (acrm 4a9a934e0): the panel, search row, rows, states, keyboard and focus are Record select's. Canon after the DoD — stories, visual baseline, audit — the shell is DS.RecordRefField in @acrm/ui (acrm !4502); this component is its data wrapper.

When to use

  • A field that links several records to a task, meeting, note or relation and shows them as tokens: participants, linked contacts and companies, deals of a meeting.
  • Server search over the whole CRM (thousands of records) with a type filter: types={PERSON_TYPES} (users + contacts + organizations, P8) or DEAL_TYPES.
  • max={1} when the relation is single but the picked record must stay visible as a token with "×" (company of a contact).

When not to use

  • One value in a field or dialog row — plain Record select (useRecordSearch for server search). One value = Record select, several record references = Entity picker.
  • A rail row — Rail picker.
  • An in-memory list (≤ a few hundred rows) where the choice is a set of options, not records — Record select multi or Select multiple.
  • Products — Product picker.

Anatomy

  • .acrm-field > .acrm-field-label (unless hideLabel) > .eref-field.
  • Tokens: <EntityRef removable> via EntityRefPreview (hover preview; name opens the record when onOpenEntity is given). Optional state after the name (statusOf): .eref-dot with tone and title, delivery status icon, short .eref-meta — meeting invitations only.
  • E-mail tokens (emails mode): a bare <EntityRef> with just the typed address — the contact is created by the server on save.
  • .eref-add > button.add-ref ("Přidat", aria-haspopup="listbox", aria-expanded), hidden once max is reached.
  • Panel: RecordSelect with anchorRef = .eref-add, keepOpen, filter={false}, onQueryChange (debounce 180 ms), minWidth={320}. Rows carry the type mark (entityType) and sub = sublabel · type label (recordTypeLabel). Already-picked records are filtered out — no check in rows.
  • States from Record select: below MENTION_MIN_QUERY "Napište alespoň N znaky", loading only without data in hand, no results.

Recent records (recent)

With recent, a query below MENTION_MIN_QUERY lists recently opened records of the allowed types (useRecentRecords, GET /search/recent, genuine detail opens) instead of the hint. Locked records and disallowed types are filtered out; same rows and same pick path as search results. First consumer: the other-side picker in RelationDialog.

Invite by e-mail (emails)

A typed valid address is offered as the first row ("Nový kontakt: …", createPosition="top", icon mail) and Enter takes it — unless a contact with exactly that address is found, which is offered instead so no duplicate contact is created. The address survives closing the panel by click outside; Esc discards it. Only New meeting uses it.

Best practices

Do

  • Pass label even with hideLabel — it names the listbox.
  • Use max={1} instead of a single-value variant when the token must stay visible.
  • Turn on recent where the user usually picks something just opened.

Don't

  • Build "tokens + Přidat + search" again around a bare Record select — that is this component.
  • A visible bordered input with tokens inside — references float, search lives in the panel.
  • Use it for one value in a form row — that is Record select.

Content

  • "Přidat" (addLabel); search placeholder from placeholder (default "Hledat…").
  • Short-query hint "Napište alespoň N znaky" is a state, not an explanation.
  • Type label in sub from recordTypeLabel ("Kolega", "Kontakt", "Firma", "Obchod").
  • record-select — the panel (adding mode, server search, onCreate top row).
  • entity-ref (variant removable) — the tokens.
  • product-picker — the same composition for the product catalog.
  • rail-picker — the rail equivalent.
  • formless-dialog — New meeting, Edit meeting, Relation, New project use it.
  • Stories: Components / Record reference field — Default · States · Composition (DS.RecordRefField, acrm !4502).

Source: docs/select/entity-picker.usage.md · GitLab