---
id: CMP-CRM-ENT-007
title: Contact Selector
product_area: crm
module: entities
revision: 1
status: draft
design_intent: proposed
implementation_evidence: observed
source_sha:
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
purpose: Lets a caller select and retain contact identifiers while the picker resolves names, handles search and
  distinguishes held inactive records.
reuse: The reusable ContactSelector supports single and multiple contact fields; Entities currently uses the ContactPicker
  form variant and CRM-source RecordPicker in Organization 360’s Add Person dialog. Consumers must choose the source
  contract deliberately.
supports:
- CAP-CRM-ENT-003
- CAP-CRM-ENT-009
realises:
- CON-CRM-ENT-001
props:
- name: value
  type: nullable identifier; identifier list for multiple selection
  required: true
  default: none
  meaning: Supplies the held contact or contacts.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: onChange
  type: selection handler
  required: true
  default: none
  meaning: Receives identifier and option for single selection, or the complete identifier list for multiple selection.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: source
  type: contact picker source
  required: false
  default: none
  meaning: Overrides the default workspace Quick Search source.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: label
  type: text
  required: false
  default: none
  meaning: Provides field label and accessible association; omission leaves labeling to the caller.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: required
  type: boolean
  required: false
  default: none
  meaning: Marks the labeled editable field and sets the trigger’s required semantics.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: description
  type: text
  required: false
  default: none
  meaning: Provides linked help text.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: error
  type: text
  required: false
  default: none
  meaning: Provides linked field error and invalid state.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: disabled
  type: boolean
  required: false
  default: none
  meaning: Disables interaction and creation.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: readOnly
  type: boolean
  required: false
  default: none
  meaning: Replaces the selector trigger with a static held-value summary.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: placeholder
  type: text
  required: false
  default: Select a contact
  meaning: Names an empty single selection.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: density
  type: compact or comfortable
  required: false
  default: none
  meaning: Selects the held summary’s detail.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: filters
  type: record filters
  required: false
  default: none
  meaning: Narrows source searches.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: allowCreate
  type: boolean
  required: false
  default: true
  meaning: Offers quick creation only with create permission and an editable enabled field.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: id
  type: control identifier
  required: false
  default: none
  meaning: Provides explicit identity; otherwise an identity is generated.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: className
  type: presentation classes
  required: false
  default: none
  meaning: Extends field presentation.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: clearable
  type: boolean
  required: false
  default: none
  meaning: Controls single-selection clearing through the shared picker.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: valueLabel
  type: text
  required: false
  default: none
  meaning: Provides single-selection fallback wording when resolution cannot name the contact.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: excludeId
  type: identifier on ContactPicker only
  required: false
  default: none
  meaning: Excludes one identifier in the older form wrapper; it is not a ContactSelector prop.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
events:
- name: change
  when: An option is selected, cleared or created.
  payload: 'Single: nullable identifier and option; multiple: full identifier list.'
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- name: form variant change
  when: The ContactPicker form variant selects or clears.
  payload: Identifier text, with an empty string for clearing.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
states:
- state: empty
  experience: A placeholder and contact search trigger appear.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- state: searching
  experience: The shared picker debounces reads and presents loading feedback.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- state: held inactive
  experience: Resolution keeps the held identifier nameable with inactive wording.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- state: refused or unavailable
  experience: The Quick Search source reports explicit access or environment errors; no database fallback is used.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- state: read only
  experience: A static summary keeps its tooltip while omitting trigger, clearing and creation.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- state: quick add
  experience: A lazy-loaded creation drawer keeps the new option locally until the search source catches up.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- state: form variant
  experience: The older wrapper uses a locally matched result set and CRM-backed source rather than the default
    Quick Search contract.
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
validation: []
accessibility: Field labels, descriptions and errors are linked to the selector trigger; editable required fields
  have a visible marker and required semantics. The quick-add drawer receives a return-focus target. The form variant
  names Clear and relies on command/popover controls. Complete keyboard, tooltip and assistive-technology behavior
  remains unverified.
design_system:
- field
- popover
- command
- button
- person summary
- tooltip
- sheet
- loading indicator
depends_on: []
implementation: CMI-CRM-ENT-007
acceptance:
- id: AC-CMP-CRM-ENT-007-01
  proved_by: []
  statement: A disabled or read-only ContactSelector offers no quick-create action.
  level: unit
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- id: AC-CMP-CRM-ENT-007-02
  proved_by: []
  statement: A permitted quick-create result is selected and remains resolvable locally before the remote index
    knows it.
  level: unit
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- id: AC-CMP-CRM-ENT-007-03
  proved_by: []
  statement: A held inactive contact can be resolved without making all inactive contacts fresh choices.
  level: unit
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- id: AC-CMP-CRM-ENT-007-04
  proved_by: []
  statement: The default Quick Search source reports unavailability instead of using a database fallback.
  level: unit
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
controls: []
evidence:
- react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
  react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
  react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
  react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
  react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
  react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
  react-console:components/contact-editor/fields/record-picker.tsx
narrative_sources:
- section: What It Is For
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- section: Where It Is Used
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- section: How It Behaves
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- section: Its Contract
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- section: States
  provenance: observed
  source: react-console:components/record-pickers/contact-selector.tsx; react-console:components/record-pickers/record-picker.tsx;
    react-console:components/record-pickers/record-multi-picker.tsx; react-console:components/record-pickers/person-option-row.tsx;
    react-console:components/record-pickers/person-summary.tsx; react-console:components/record-pickers/new-contact-drawer.tsx;
    react-console:lib/record-pickers/quick-search-contact-source.ts; react-console:lib/record-pickers/sources.ts;
    react-console:lib/record-pickers/crm-adapter.ts; react-console:lib/record-pickers/source.ts; react-console:lib/record-pickers/inactive.ts;
    react-console:lib/record-pickers/types.ts; react-console:components/contact-editor/fields/entity-pickers.tsx;
    react-console:components/contact-editor/fields/record-picker.tsx
- section: Accessibility
  provenance: unknown
  source: FND-CRM-ENT-161
- section: Open Design Questions
  provenance: unknown
  source: FND-CRM-ENT-161; FND-CRM-ENT-162; FND-CRM-ENT-163
used_by: []
---

# Contact Selector

## What It Is For

Lets a caller select and retain contact identifiers while the picker resolves names, handles search and distinguishes held inactive records. The console has a named ContactSelector, its multiple-selection counterpart and an older ContactPicker form wrapper. The named selector defaults to Quick Search and can open a lazy contact creation drawer. Entities’ current affiliation picker supplies a CRM source directly to the generic RecordPicker. The record captures these variants without inventing a separate organization-style contact control.

## Where It Is Used

The reusable ContactSelector supports single and multiple contact fields; Entities currently uses the ContactPicker form variant and CRM-source RecordPicker in Organization 360’s Add Person dialog. Consumers must choose the source contract deliberately. ContactSelector is available to reusable form consumers, while current Entities contact forms use the older ContactPicker for contact-valued fields. Organization 360’s Add Person dialog uses RecordPicker with the CRM contact source. The source and prop differences must remain visible when those screens are wired to this design.

## How It Behaves

ContactSelector wraps the shared picker with a labeled field, supplied help and errors. Without an override it uses the signed-in workspace’s Quick Search source. Held identifiers resolve separately from fresh search choices, allowing an inactive or archived held record to remain named. A permitted editable field can offer Add New Contact; successful creation remembers the option locally and selects it immediately. ContactMultiSelector uses the same field contract with chips and a complete replacement identifier list. These wrappers are separate from the older contact-form picker and the CRM-source picker supplied to Organization 360.

## Its Contract

The source supplies search, resolution and recent identifiers; the caller supplies the held value and receives selection changes. The default Quick Search source does not fall back to a database when access or the index is unavailable. An explicit source can replace that transport. The older ContactPicker accepts an empty-string value and optional excluded identifier, returns only identifier text and filters locally over source results. Organization-side affiliation addition supplies a CRM contact source directly to the shared RecordPicker. These differences are observed contracts rather than a uniform implementation claim.

## States

Empty: A placeholder and contact search trigger appear. Searching: The shared picker debounces reads and presents loading feedback. Held inactive: Resolution keeps the held identifier nameable with inactive wording. Refused or unavailable: The Quick Search source reports explicit access or environment errors; no database fallback is used. Read only: A static summary keeps its tooltip while omitting trigger, clearing and creation. Quick add: A lazy-loaded creation drawer keeps the new option locally until the search source catches up. Form variant: The older wrapper uses a locally matched result set and CRM-backed source rather than the default Quick Search contract.

## Accessibility

Field labels, descriptions and errors are linked to the selector trigger; editable required fields have a visible marker and required semantics. The quick-add drawer receives a return-focus target. The form variant names Clear and relies on command/popover controls. Complete keyboard, tooltip and assistive-technology behavior remains unverified. Accessibility verification is an open obligation recorded in the component accessibility finding.

## Open Design Questions

The recorded interaction is observed implementation, with proposed design intent. Component criteria need complete executable bindings and browser accessibility review. Screen owners must wire the registered components into their designs; this slice records usage without changing those screen contracts.
