Skip to content

Inspector

<caos-inspector>

properties of the current selection, edited in place

May be placed on a record page and a page inside an app.

Name Attribute Description Type Default Required
heading heading, markup only What the panel is about, usually the name of the selected thing. It is also what names the panel for a screen reader, so a panel with no heading is an unlabelled region. text none declared Optional
closable closable, markup only Show the close control in the header. It only REQUESTS the close — the panel does not remove itself, so the surface that owns the panel decides what closing means. boolean false Optional
modal modal, markup only Put it inside an Overlay rather than leaving it a complementary landmark: it floats over a scrim, takes focus when it is connected, traps Tab, closes on Escape and on a scrim click, and hands focus back to whatever opened it. The dialog is labelled with the heading and it always shows the close control. boolean false Optional
Name When it fires What it carries
caos-inspector-close The close control is pressed, or — while it is modal — Escape is pressed or the scrim is clicked. However it was asked for, it arrives under this one name. It is a request and it is cancelable — the panel never removes itself. nothing
Name What goes in it
the default slot The body: the properties of the selection. The panel pads it, so what goes in is the fields themselves — field renderers, key-value rows, detail sections — and not a padded wrapper.
actions Controls that belong to the panel as a whole, sitting in the header beside the heading.
Design token What it controls
--caos-color-surface The fill of the panel and of its header.
--caos-color-surface-2 The hover fill of the close control.
--caos-color-border The panel edge and the divider under the header.
--caos-color-text The heading text.
--caos-color-text-muted The resting colour of the close control.
--caos-shadow-float The elevation of the modal variant, drawn by the Overlay it sits in. A plain panel does not float and has none.
--caos-radius-lg The corner radius of the panel.
--caos-radius-sm The corner radius of the close control.
--caos-focus-ring The ring on the close control when it is reached by keyboard.
--caos-font-display The typeface the heading is set in.
--caos-space-2 The gap between the controls in the actions slot.
--caos-space-3 The header padding and the gap between heading, actions and close.
--caos-space-4 The padding of the body and the horizontal padding of the header.
Name Description Arguments
requestClose() Raise the close request from code, the same way the close control and Escape do — for a Done button in the actions slot, so one path decides what closing means. takes none

Nothing on this piece can be read back.

Part Which piece of it When it is there
::part(panel) the panel Always
::part(header) the header strip Always
::part(title) the heading Always
::part(actions) the action group in the header Always
::part(close) the close control Always
::part(body) the scrolling body Always

Something is selected and its properties are edited right there, with the surface that holds the selection still visible and still in play behind the panel.

  • DetailSection — The fields belong in the body of the record page itself, in the section the layout puts them in.
  • Overlay — The panel has to take the screen: a scrim over the page, a centred or edge placement, and focus handed back to whatever opened it.
  • SplitView — You are laying out the two panes themselves — a list on the left and the record on the right.

The panel is a role=“complementary” landmark named by its heading, so it is reachable as a region and announced for what it is. Set modal and it goes inside an Overlay, which is the role=“dialog” with aria-modal: focus moves in on open and Tab is trapped within it, piercing slotted custom elements so a button whose real control lives in its own shadow root is still in the ring, and focus returns to whatever opened it on close; Escape raises the close. The close control is a real button with an accessible name. What is left to the author: give it a heading and act on the close event, which is the one name every dismissal arrives under — the close control, Escape, or the scrim.

The panel doing what its purpose line says: the fields of the selected record as editable controls, with the one value nobody edits left as a plain row.

The page around it: removes the panel when it reports a close, because the piece raises the request and the surface decides the outcome

{
"id": "example",
"section": "Properties of a selection",
"columns": 1,
"items": [
{
"id": "inspector_1",
"type": "component",
"key": "inspector",
"inputs": {
"heading": "ORD-4471",
"closable": true
},
"children": [
{
"id": "key_value_row_2",
"type": "component",
"key": "key_value_row",
"inputs": {
"label": "Reference",
"value": "ORD-4471"
}
},
{
"id": "field_renderer_3",
"type": "component",
"key": "field_renderer",
"inputs": {
"mode": "edit",
"field": {
"storageType": "Text",
"label": "Account",
"required": true
},
"value": "Meridian Supply"
}
},
{
"id": "field_renderer_4",
"type": "component",
"key": "field_renderer",
"inputs": {
"mode": "edit",
"field": {
"storageType": "Text",
"label": "Stage"
},
"value": "In review"
}
},
{
"id": "field_renderer_5",
"type": "component",
"key": "field_renderer",
"inputs": {
"mode": "edit",
"field": {
"storageType": "Number",
"format": "currency",
"label": "Total",
"scale": 2
},
"value": 12400
}
}
]
}
]
}
<caos-inspector heading="ORD-4471" closable>
<caos-key-value-row label="Reference" value="ORD-4471"></caos-key-value-row>
<caos-field-renderer id="inspector1fieldRenderer2" mode="edit" value="Meridian Supply"></caos-field-renderer>
<caos-field-renderer id="inspector1fieldRenderer3" mode="edit" value="In review"></caos-field-renderer>
<caos-field-renderer id="inspector1fieldRenderer4" mode="edit" value="12400"></caos-field-renderer>
</caos-inspector>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const inspector1fieldRenderer2 = document.getElementById('inspector1fieldRenderer2');
const inspector1fieldRenderer3 = document.getElementById('inspector1fieldRenderer3');
const inspector1fieldRenderer4 = document.getElementById('inspector1fieldRenderer4');
inspector1fieldRenderer2.field = {
"storageType": "Text",
"label": "Account",
"required": true
};
inspector1fieldRenderer3.field = {
"storageType": "Text",
"label": "Stage"
};
inspector1fieldRenderer4.field = {
"storageType": "Number",
"format": "currency",
"label": "Total",
"scale": 2
};

Controls belonging to the panel as a whole, in the actions slot beside the heading — where they sit apart from the fields and stay put while the body scrolls.

{
"id": "example",
"section": "With header actions",
"columns": 1,
"items": [
{
"id": "inspector_1",
"type": "component",
"key": "inspector",
"inputs": {
"heading": "ORD-4471"
},
"children": [
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "ghost",
"size": "sm"
},
"slot": "actions",
"children": [
"Revert"
]
},
{
"id": "button_3",
"type": "component",
"key": "button",
"inputs": {
"variant": "primary",
"size": "sm"
},
"slot": "actions",
"children": [
"Save"
]
},
{
"id": "key_value_row_4",
"type": "component",
"key": "key_value_row",
"inputs": {
"label": "Account",
"value": "Meridian Supply"
}
},
{
"id": "key_value_row_5",
"type": "component",
"key": "key_value_row",
"inputs": {
"label": "Total",
"value": "$12,400"
}
}
]
}
]
}
<caos-inspector heading="ORD-4471">
<caos-button slot="actions" variant="ghost" size="sm">Revert</caos-button>
<caos-button slot="actions" variant="primary" size="sm">Save</caos-button>
<caos-key-value-row label="Account" value="Meridian Supply"></caos-key-value-row>
<caos-key-value-row label="Total" value="$12,400"></caos-key-value-row>
</caos-inspector>