Lookup Field
Reference field for linking to other objects/records
The Lookup Field component provides a reference field for creating relationships between objects and records. It supports dynamic data loading from a DataSource with debounced search, loading/error/empty states, keyboard navigation, and optional quick-create entry.
Basic Usage
Basic Lookup
{
"type": "lookup",
"name": "assigned_to",
"label": "Assigned To",
"placeholder": "Select user...",
"reference_to": "users",
"options": [
{
"label": "John Doe",
"value": "user_1"
},
{
"label": "Jane Smith",
"value": "user_2"
},
{
"label": "Bob Johnson",
"value": "user_3"
}
]
}Multiple References
Multi-Select Lookup
{
"type": "lookup",
"name": "team_members",
"label": "Team Members",
"placeholder": "Select team members...",
"reference_to": "users",
"multiple": true,
"options": [
{
"label": "Alice Brown",
"value": "user_4"
},
{
"label": "Charlie Davis",
"value": "user_5"
},
{
"label": "Diana Wilson",
"value": "user_6"
}
]
}Field Schema
interface LookupFieldSchema {
type: 'lookup' | 'master_detail';
name: string; // Field name/ID
label?: string; // Field label
placeholder?: string; // Placeholder text
value?: string | string[]; // Default value(s)
multiple?: boolean; // Allow multiple selections
required?: boolean; // Is field required
readonly?: boolean; // Read-only mode
disabled?: boolean; // Disabled state
className?: string; // Additional CSS classes
// Reference Configuration
reference_to: string; // Referenced object/table name
reference_field?: string; // Field to display (default: 'name')
description_field?: string; // Secondary field shown below label
id_field?: string; // ID field on records (default: '_id')
options?: LookupOption[]; // Available options (if static)
// Data Source (automatic via SchemaRendererContext, or explicit)
// When a DataSource is available, the popup dynamically loads
// records from the referenced object on open, with debounced search.
dataSource?: DataSource;
// Quick-create callback (shown when no results found)
onCreateNew?: (searchQuery: string) => void;
// === Record Picker Configuration (Enterprise) ===
// Columns to show in the Record Picker dialog table.
// Accepts field names or { field, label, width } objects.
// When omitted, auto-infers from reference_field.
lookup_columns?: Array<string | { field: string; label?: string; width?: string }>;
// Custom page size for the Record Picker dialog (default: 10)
lookup_page_size?: number;
}
interface LookupOption {
label: string; // Display label
value: string; // Record ID
description?: string; // Secondary text below label
_id?: string; // Alternative ID field
name?: string; // Alternative label field
}Dynamic Data Source
When a DataSource is available (via SchemaRendererContext, explicit prop, or field config), the Lookup popup automatically fetches records from the referenced object:
// Automatic — DataSource from SchemaRendererContext
// (works out-of-the-box in ObjectForm, DrawerForm, etc.)
{
type: 'lookup',
name: 'customer',
label: 'Customer',
reference_to: 'customers',
reference_field: 'name', // Display field (default: 'name')
description_field: 'industry', // Optional secondary field
}The popup will:
- Fetch records via
dataSource.find(reference_to, { $top: 50 })on open - Send
$searchqueries with 300ms debounce as the user types - Show loading spinner, error state with retry, and empty state
- Display "Showing X of Y" when more records exist than the page size
- Show a "Show All Results" button (inside the popover) to open the full Record Picker dialog when total exceeds page size
Browse All Button
Every Lookup field with a dataSource always renders a "Browse All" button (table icon) next to the quick-select trigger. This button opens the full RecordPickerDialog directly, regardless of dataset size — ensuring enterprise features like multi-column tables, sort/filter bar, and cell renderers are always discoverable.
- Always visible when
dataSourceis configured - Opens the Record Picker dialog without needing to open the popover first
- Keyboard accessible and screen-reader friendly (
aria-label="Browse all records")
Record Picker Dialog (Enterprise)
The full RecordPickerDialog can be opened in two ways:
- "Browse All" button (table icon) — always visible next to the quick-select trigger
- "Show All Results" link inside the popover — shown when total records exceed the page size
// Configure the Record Picker with lookup_columns
{
type: 'lookup',
name: 'order',
label: 'Order',
reference_to: 'orders',
reference_field: 'order_number',
description_field: 'customer_name',
lookup_columns: [
{ field: 'order_number', label: 'Order #' },
{ field: 'customer_name', label: 'Customer' },
{ field: 'total_amount', label: 'Amount' },
{ field: 'status', label: 'Status' },
],
lookup_page_size: 15,
}The Record Picker dialog provides:
- Multi-column table with configurable columns via
lookup_columns - Search with debounced server-side querying
- Column sorting via clickable headers (sends
$orderbyto DataSource) - Pagination with page-by-page navigation
- Keyboard navigation — Arrow keys to move between rows, Enter/Space to select
- Single/Multi-select with visual check indicators and confirmation flow
- Responsive layout — Mobile-friendly width (95vw on small screens)
- Loading, error, and empty states
- Auto-inferred columns from
reference_fieldwhenlookup_columnsis not set
Lookup vs Master-Detail
- Lookup: Standard reference field, can be deleted independently
- Master-Detail: Parent-child relationship, deleting parent deletes children
Cell Renderer
In tables/grids, lookup values display the referenced record name:
import { LookupCellRenderer } from '@object-ui/fields';
// Single value: Display name/label
// Multiple values: Multiple chips/badgesUse Cases
- Assignments: Assign tasks to users
- Relationships: Link related records
- Categories: Reference to category objects
- Parent Records: Master-detail relationships
- Team Members: Multi-user references
Features
- Two-Level Interaction: Popover typeahead (Level 1) + full Record Picker dialog (Level 2)
- Record Picker Dialog: Enterprise-grade table with multi-column, pagination, search, sorting
- Inline Popover: Level 1 opens as anchored dropdown (non-modal) for fast typeahead
- Column Sorting: Clickable column headers with
$orderbyserver-side sort - Dynamic DataSource Loading: Automatically fetches records from referenced objects
- Search: Debounced type-ahead search with
$searchparameter - Multi-Select: Support for multiple references with confirmation flow
- Keyboard Navigation: Arrow keys to navigate rows, Enter to select in both levels
- Responsive: Mobile-friendly width, adapts to screen size
- Loading/Error/Empty States: Friendly feedback for all states
- Secondary Field Display: Show description/subtitle per option
- Quick-Create Entry: Optional "Create new" button when no results
- Configurable Columns:
lookup_columnsfor multi-column picker display - Base Filters:
lookup_filtersto restrict selectable records - Pagination: Page-by-page navigation in Record Picker dialog
- Backward Compatible: Falls back to static options when no DataSource