RecordFieldInspector
<caos-record-field-inspector>
one record as a flat, sortable, in-place editable list of all its fields
May be placed on a page inside an app and a record page.
Inputs
Section titled “Inputs”| Name | Attribute | Description | Type | Default | Required |
|---|---|---|---|---|---|
fields |
property only | Every field of the record: { apiName, label, type, value?, lock? }[]. lock is why a field cannot be edited — computed, no-permission or masked — and each reads as its own sentence in the row, because those three need different things from the reader. |
json | empty list | Optional |
recordId |
record-id, markup only |
Which record this is. Changing it CLEARS the pending edits — carrying them across would write one record’s half-finished changes onto another. | recordId | none declared | Optional |
search |
search, markup only |
Narrows the rows by API name, label or type. Reflected, so it can be linked to. | text | none declared | Optional |
saving |
saving, markup only |
A save is in flight: Save reads “Saving…” and every action is held. | boolean | false | Optional |
deletable |
deletable, markup only |
Show the delete control. Absent ⇒ hidden rather than disabled: a control for something this person cannot do is a question they should not have to ask. | boolean | false | Optional |
sortKey |
sort-key, markup only |
Which of the four columns the rows are ordered by. All four matter: looking for a field by API name, by label, by type, and looking for which ones have values in them are four different searches, and a fixed order serves at most one. | text — one of apiName, label, type, value | apiName | Optional |
sortDirection |
sort-direction, markup only |
Which way. Empty values sort last in both directions. | text — one of asc, desc | asc | Optional |
Events
Section titled “Events”| Name | When it fires | What it carries |
|---|---|---|
caos-field-edit |
A value is typed into. Fires for each change, including one that returns a field to its original. | { apiName, value, dirty }. |
caos-record-save |
Save is pressed. Never while saving, and never with nothing changed. |
{ recordId, changes } — changes holds ONLY the fields that changed. A component handing back every field it was given would make every save a full overwrite. |
caos-record-discard |
Discard is pressed with changes pending. | nothing |
caos-record-export |
Export is pressed. | { recordId, fields } — the fields as currently filtered and ordered. |
caos-record-delete |
The delete control is pressed. | { recordId }. It ASKS: whether a record can be deleted, and what warning that deserves, is not a component’s call, and an irreversible act behind an unconfirmed click is not one either. |
Not documented yet — this piece has not said.
Styling hooks
Section titled “Styling hooks”Not documented yet — this piece has not said.
Methods
Section titled “Methods”| Name | Description | Arguments |
|---|---|---|
accept() |
Clear the pending edits. What a host calls once a save has actually landed — the component does not assume its own event succeeded. | takes none |
Readable state
Section titled “Readable state”| Name | Type | What it tells you |
|---|---|---|
pending |
{ [apiName]: string } | The changed fields and their new values. Empty when nothing is pending. |
dirty |
boolean | Whether anything is pending. A comparison against the values handed in, not a flag somebody sets — so typing a value and typing the original back leaves it false. |
visibleFields |
CaosRecordField[] | The fields after the search, in the current order. |
Styling parts
Section titled “Styling parts”| Part | Which piece of it | When it is there |
|---|---|---|
::part(inspector) |
The outer column. | Always |
::part(toolbar) |
The search and action row. | Always |
::part(search) |
The search box. | Always |
::part(actions) |
The save / discard / export / delete cluster. | Always |
::part(summary) |
The field count and unsaved-change line. | Always |
::part(table) |
The composed data table. | Always |
::part(value-input) |
The editor in one value cell. | The field is not locked. |
::part(reason) |
The text in a locked field’s value cell. | The field is locked. |
When to use it
Section titled “When to use it”When somebody needs the WHOLE record — API names included — rather than the fields a layout chose to show. Debugging, data fixing, and answering “is that field even populated”.
What to use instead
Section titled “What to use instead”- FieldRenderer — the fields are being presented to a person doing their job, where the layout, the labels and the typed controls are the point. This is the developer’s flat view of the same record.
- KeyValueRow — a handful of named values are being read and nothing is being edited.
Accessibility
Section titled “Accessibility”Every value editor carries an accessible name reading the label and the API name, so a row read aloud says which field is being edited rather than announcing an unlabelled text box. The summary is a role="status" live region, so the number of unsaved changes is announced as it moves — somebody editing down a long list is not looking at the header. A locked field shows the reason as text in its own cell rather than as a disabled control, because “you cannot” is the half a reader already worked out and “the platform computes it” is the half they need.
Examples
Section titled “Examples”A record with a change pending
Section titled “A record with a change pending”The flat view: API name, label, type and value, with one field edited and not yet saved. Save and Discard are both enabled, and the summary counts the change.
{ "id": "example", "section": "A record with a change pending", "columns": 1, "items": [ { "id": "record_field_inspector_1", "type": "component", "key": "record_field_inspector", "inputs": { "record_id": "001x00000A1b2C", "deletable": true, "fields": [ { "apiName": "Id", "label": "Record Id", "type": "Id", "value": "001x00000A1b2C", "lock": "computed" }, { "apiName": "Name", "label": "Account Name", "type": "Text", "value": "Northwind Traders" }, { "apiName": "Industry", "label": "Industry", "type": "Picklist", "value": "Retail" }, { "apiName": "AnnualRevenue", "label": "Annual Revenue", "type": "Currency", "value": 4200000 }, { "apiName": "Website", "label": "Website", "type": "Url", "value": null }, { "apiName": "CreatedDate", "label": "Created Date", "type": "DateTime", "value": "2025-03-04T09:11:00Z", "lock": "computed" } ] } } ]}<caos-record-field-inspector id="recordFieldInspector1" record-id="001x00000A1b2C" deletable></caos-record-field-inspector>// What an attribute cannot hold, set as a property — the same values the preview is drawn with.const recordFieldInspector1 = document.getElementById('recordFieldInspector1');recordFieldInspector1.fields = [ { "apiName": "Id", "label": "Record Id", "type": "Id", "value": "001x00000A1b2C", "lock": "computed" }, { "apiName": "Name", "label": "Account Name", "type": "Text", "value": "Northwind Traders" }, { "apiName": "Industry", "label": "Industry", "type": "Picklist", "value": "Retail" }, { "apiName": "AnnualRevenue", "label": "Annual Revenue", "type": "Currency", "value": 4200000 }, { "apiName": "Website", "label": "Website", "type": "Url", "value": null }, { "apiName": "CreatedDate", "label": "Created Date", "type": "DateTime", "value": "2025-03-04T09:11:00Z", "lock": "computed" }];The three reasons a field cannot be edited
Section titled “The three reasons a field cannot be edited”Computed by the platform, not permitted to this person, and masked. Each says which, because they need different things from the reader and a greyed box says none of it.
{ "id": "example", "section": "The three reasons a field cannot be edited", "columns": 1, "items": [ { "id": "record_field_inspector_1", "type": "component", "key": "record_field_inspector", "inputs": { "record_id": "001x00000A1b2C", "fields": [ { "apiName": "Name", "label": "Account Name", "type": "Text", "value": "Northwind Traders" }, { "apiName": "LastModifiedDate", "label": "Last Modified", "type": "DateTime", "value": "2026-09-02T14:00:00Z", "lock": "computed" }, { "apiName": "CreditRating__c", "label": "Credit Rating", "type": "Text", "value": "A-", "lock": "no-permission" }, { "apiName": "TaxId__c", "label": "Tax Id", "type": "Text", "value": "99-1234567", "lock": "masked" } ] } } ]}<caos-record-field-inspector id="recordFieldInspector1" record-id="001x00000A1b2C"></caos-record-field-inspector>// What an attribute cannot hold, set as a property — the same values the preview is drawn with.const recordFieldInspector1 = document.getElementById('recordFieldInspector1');recordFieldInspector1.fields = [ { "apiName": "Name", "label": "Account Name", "type": "Text", "value": "Northwind Traders" }, { "apiName": "LastModifiedDate", "label": "Last Modified", "type": "DateTime", "value": "2026-09-02T14:00:00Z", "lock": "computed" }, { "apiName": "CreditRating__c", "label": "Credit Rating", "type": "Text", "value": "A-", "lock": "no-permission" }, { "apiName": "TaxId__c", "label": "Tax Id", "type": "Text", "value": "99-1234567", "lock": "masked" }];