LookupField
<caos-lookup-field>
a field pointing at another record — reads as a link, re-points through a typeahead picker
May be placed on a record page, a page inside an app and a step of a guided flow.
Inputs
Section titled “Inputs”| Name | Attribute | Description | Type | Default | Required |
|---|---|---|---|---|---|
mode |
mode, markup only |
Which half to draw: read for the link, edit for the typeahead. Anything else reads as read. |
text — recognises read, edit; anything else reads as read |
read | Optional |
search |
property only | The result source — (query, request) => options or a promise of them, where an option is { value, label, sublabel?, href?, fields? }. The second argument carries what the surface asked for, including the fields the query should be matched against; a source written for the one-argument shape keeps working and simply ignores it. Set it as a property. Whatever it returns is offered, so it is this function that has to be scoped to what the current person may read. |
json | none declared | Optional |
matchFields |
match-fields, markup only |
Which fields the typing is matched against, as a comma-separated list handed straight to the search seam — “name, account_number”. A lookup that matches only on a name cannot find a record by its number, and the surface is what knows which is which. Saying nothing leaves the decision to the source, which is what every source decided on its own before. | text | none declared | Optional |
displayFields |
display-fields, markup only |
Which of a result’s own fields are drawn on its second line, as a comma-separated list — “industry, city” — joined in the order given. This is how two records with the same name are told apart. An option that supplies an explicit sublabel keeps it: a source that has already decided what the second line says was not asked to reconsider. | text | none declared | Optional |
minChars |
min-chars, markup only |
How much has to be typed before the source is asked at all. Under it the list says what is needed rather than offering everything. Zero — ask from the first keystroke, and from an empty box — is what this control did before and is still the default. | number | 0 | Optional |
searchDelay |
search-delay, markup only |
Milliseconds to wait after the last keystroke before asking, so a fast typist makes one request rather than eight. Raise it for a source that is expensive to ask. | number | 150 | Optional |
value |
value, also a property |
The id of the record pointed at. Written back when an option is chosen, and removed on clear. | recordId | none declared | Optional |
display |
display, also a property |
The linked record’s name — what read mode actually draws. Without it the link falls back to showing the raw id, which is the one thing this piece exists to avoid. | text | none declared | Optional |
href |
href, markup only |
Where the read-mode link goes. Left unset the name is still drawn and still reachable by keyboard, as a trigger for re-pointing rather than as navigation. | text | none declared | Optional |
label |
label, markup only |
The field’s name, drawn above the control and pointed at the input, so clicking it focuses the typeahead. It is also used as the accessible name. | text | none declared | Optional |
placeholder |
placeholder, markup only |
Two jobs, one word: the hint inside the empty typeahead in edit mode, and what read mode shows when nothing is linked. Read mode falls back to an em dash. | text | Search… | Optional |
required |
required, markup only |
A record has to be pointed at. Draws the asterisk beside the label. | boolean | false | Optional |
disabled |
disabled, markup only |
The link may not be changed. Greys the typeahead and refuses focus. It does not affect read mode. | boolean | false | Optional |
invalid |
invalid, markup only |
The link is wrong or missing. Turns the outline and the message red and marks the input invalid. | boolean | false | Optional |
message |
message, markup only |
The line under the control — muted helper text on its own, the red reason when invalid is also set. |
text | none declared | Optional |
inline |
inline, markup only |
Draw the record-detail variant: no box, an accent underline, inheriting the surrounding type, with the search glyph and the clear control pulled to the edges. The label and the message are hidden. | boolean | false | Optional |
Events
Section titled “Events”| Name | When it fires | What it carries |
|---|---|---|
caos-lookup-change |
When an option is chosen — clicked, or Enter on the active one. The list closes and the input takes the chosen name. | { value, label } — the id now pointed at and the name being shown for it. |
caos-lookup-clear |
When the clear control is pressed. The link is dropped, the input is emptied and focus returns to it. | nothing |
Nothing goes inside this piece.
Styling hooks
Section titled “Styling hooks”| Design token | What it controls |
|---|---|
--caos-font |
The typeface of the label, the link, the typeahead and the message. |
--caos-text-body |
The size of the label, the link and the typed query. |
--caos-text-row |
The size of an option label in the list. |
--caos-space-1 |
The gap between the label, the control and the message, and the padding inside the list. |
--caos-space-2 |
The inset of the clear control, and the vertical padding of an option. |
--caos-space-3 |
The padding inside the typeahead and the horizontal padding of an option. |
--caos-space-4 |
The left inset of the typeahead in the inline variant, clearing its search glyph. |
--caos-space-5 |
With the smaller spaces, the room the typeahead keeps for its glyph and its clear control. |
--caos-radius |
The corner radius of the typeahead and of the results list. |
--caos-radius-sm |
The corner radius of an option, of the clear control and of the link focus ring. |
--caos-color-border |
The outline of the typeahead at rest, and the edge of the results list. |
--caos-color-border-strong |
The outline of the typeahead while it has focus. |
--caos-color-surface |
The fill of the results list, and the ground the selected option is mixed into. |
--caos-color-surface-2 |
The fill of the typeahead, and the highlight on the option the keyboard is on. |
--caos-color-text |
The typed query and an option label. |
--caos-color-text-muted |
The field label, the search glyph, the placeholder, an option sublabel, the status line and the message. |
--caos-color-accent |
The hover outline, the underline of the inline variant, and the tint on the already-chosen option. |
--caos-color-accent-strong |
The colour of the read-mode link. |
--caos-accent-wash |
The tint that fills the typeahead while it has focus, in place of a focus ring. |
--caos-focus-ring |
The ring on the read-mode link and on the clear control. |
--caos-shadow-float |
The shadow that lifts the results list off the page. |
--caos-color-danger |
The required asterisk, and the outline and message when invalid. |
Methods
Section titled “Methods”| Name | Description | Arguments |
|---|---|---|
focus() |
Move keyboard focus to the typeahead. Focusing it re-runs the search when there is already a query in it, so the list comes back rather than staying shut. | options: FocusOptions |
Readable state
Section titled “Readable state”| Name | Type | What it tells you |
|---|---|---|
open |
boolean | Whether the results list is showing. |
Styling parts
Section titled “Styling parts”| Part | Which piece of it | When it is there |
|---|---|---|
::part(label) |
the label above the control | Always |
::part(link) |
the linked record in read mode | Always |
::part(combo) |
the combobox in edit mode | Always |
::part(icon) |
the search glyph inside the box | Always |
::part(input) |
the text input | Always |
::part(clear) |
the control that clears the selection | Always |
::part(listbox) |
the results list | Always |
::part(option) |
one result | Always |
::part(message) |
the line under the control | Always |
When to use it
Section titled “When to use it”The value is another RECORD, and there are too many of them to list. Read mode wherever a record shows what it is linked to; edit mode wherever that link can be changed.
What to use instead
Section titled “What to use instead”- PicklistField — The options are a short fixed list that can simply be handed over, rather than something searched.
- FieldRenderer — The type is not known until the record is read — hand it the field metadata and it draws this piece for a Reference, in whichever mode it was given.
- KeyValueRow — The link only has to be read and never re-pointed, and it sits among other read-only rows.
- ObjectCaret — The person is navigating to a record rather than choosing one to store on this one.
- TextField — What is being captured is somebody else’s reference number, not a record in this system.
Accessibility
Section titled “Accessibility”The typeahead is a real combobox: role="combobox" with aria-expanded, aria-controls and aria-autocomplete="list" over a role="listbox" of options, and the arrow keys move an aria-activedescendant rather than moving DOM focus, so what the person is typing never leaves the box. Enter selects, Escape closes, Home and End jump to the ends, the list scrolls the active option into view, and the list closes when focus leaves the whole piece — including out of the shadow root, which is checked through the deep active element rather than assumed. The clear control carries its own name, the input has a generated id its label points at, and the searching and no-matches lines are real content in the list rather than an empty box. What is left to the author is the option LABELS and sublabels — two accounts with the same name are told apart only by the sublabel — and display, without which the link announces an id.
Examples
Section titled “Examples”The link
Section titled “The link”Read mode: the linked record drawn as its name, in the accent, never as the id underneath it.
{ "id": "example", "section": "The link", "columns": 1, "items": [ { "id": "lookup_field_1", "type": "component", "key": "lookup_field", "inputs": { "mode": "read", "label": "Account", "value": "acc-meridian", "display": "Meridian Supply", "href": "#" } } ]}<caos-lookup-field mode="read" label="Account" value="acc-meridian" display="Meridian Supply" href="#"></caos-lookup-field>Nothing linked yet
Section titled “Nothing linked yet”The same read mode with no record pointed at — an em dash, or whatever the placeholder says, rather than an empty gap.
{ "id": "example", "section": "Nothing linked yet", "columns": 1, "items": [ { "id": "lookup_field_1", "type": "component", "key": "lookup_field", "inputs": { "mode": "read", "label": "Account" } }, { "id": "lookup_field_2", "type": "component", "key": "lookup_field", "inputs": { "mode": "read", "label": "Parent account", "placeholder": "Not set" } } ]}<caos-lookup-field mode="read" label="Account"></caos-lookup-field><caos-lookup-field mode="read" label="Parent account" placeholder="Not set"></caos-lookup-field>Re-pointing it
Section titled “Re-pointing it”Edit mode doing its job: type a letter, the results open, the arrow keys roam them, and the clear control appears once something is linked.
The page around it: supplies the search — three accounts filtered by name. A placement stores values, and a function is not one, so the results always come from the page around this field rather than from the field itself.
{ "id": "example", "section": "Re-pointing it", "columns": 1, "items": [ { "id": "lookup_field_1", "type": "component", "key": "lookup_field", "inputs": { "mode": "edit", "label": "Account", "placeholder": "Search accounts…", "value": "acc-meridian", "display": "Meridian Supply" } } ]}<caos-lookup-field mode="edit" label="Account" placeholder="Search accounts…" value="acc-meridian" display="Meridian Supply"></caos-lookup-field>