Skip to content

ObjectCaret

<caos-object-caret>

the per-tab dropdown of what you can do with that object

May be placed on a seam in the workspace frame.

Name Attribute Description Type Default Required
recents property only The object’s recently-viewed records, as { id, label, href }. An empty list omits the “Recently Viewed” section entirely rather than drawing an empty one. json empty list Optional
views property only The object’s list views, as { id, label, href } — the built-in “All …” plus whatever this person has saved. The “List Views” section is always drawn, even when the list is empty. json none declared Optional
Name When it fires What it carries
caret-navigate A record or a list view was chosen. The menu closes itself; going there is the host’s half. { href } — the route the chosen row named.
caret-close The menu was dismissed — by Escape, by a click outside it, or by choosing a row. nothing

Nothing goes inside this piece.

Design token What it controls
--caos-color-surface The panel’s background.
--caos-color-surface-2 A row’s fill on hover, and on keyboard focus.
--caos-color-border The panel’s outline.
--caos-color-text The record and list-view labels.
--caos-color-text-muted The “Recently Viewed” and “List Views” section labels and their glyphs.
--caos-focus-ring The ring on a row reached by keyboard.
--caos-font The typeface inside the panel.
--caos-font-mono The two section labels.
--caos-radius The panel’s corner radius.
--caos-radius-sm The corner radius of a row’s hover and focus fill.
--caos-shadow-float The shadow that lifts the panel off the page.
Name Description Arguments
openAt() Open the menu under a caret at its live screen rectangle. Re-renders the panel from whatever recents and views currently hold, clamps itself into the viewport, and follows the anchor while the page scrolls or the window resizes. anchor: { left: number; bottom: number }
hide() Close the menu. Idempotent, and raises caret-close so the host can drop whatever state it was holding about which tab was open. restoreFocus: boolean

Nothing on this piece can be read back.

This piece exposes none of its insides to a stylesheet.

Only as the tab row’s per-object menu. If you want a dropdown of your own somewhere on a page, this is not it — this piece has no trigger and expects a caller to drive it.

  • OverflowMenu — You want a menu of ACTIONS with its own trigger, on a record or a row.
  • WorkspaceTabs — You want the tab row itself — it is the thing that raises the event this menu answers.
  • AppLauncher — The list is of apps and objects to move between, not of one object’s records and views.

The panel is a role="menu" and every row is a real role="menuitem" button, so rows are reachable and activatable from the keyboard, the section glyphs are decorative, and Escape or a click outside closes the menu and reports it. Focus moves to the first row when it opens, Tab and Shift+Tab stay inside the menu and wrap at either end, and Escape or choosing a row hands focus back to whatever held it when the menu opened — the caret on the tab; a click outside leaves focus where the click put it. What is left to the caller is the part that needs the trigger: arrow keys do not roam the rows, and the caret that opened it is where aria-expanded would have to be kept in step.

The full menu for an object somebody has been working in: the records they saw most recently, then that object’s list views.

The page around it: The surrounding page stands in for the tab row: the button plays the tab’s caret, and pressing it opens this menu at that button’s own screen rectangle — exactly what the shell does.

{
"id": "example",
"section": "Recents and views",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary"
},
"children": [
"Accounts ⌄"
]
},
{
"id": "object_caret_2",
"type": "component",
"key": "object_caret",
"inputs": {
"recents": [
{
"id": "a1",
"label": "Meridian Supply",
"href": "/sales-atlas/account/a1"
},
{
"id": "a2",
"label": "Calder & Finch",
"href": "/sales-atlas/account/a2"
}
],
"views": [
{
"id": "v1",
"label": "All Accounts",
"href": "/sales-atlas/account?view=all"
},
{
"id": "v2",
"label": "My Accounts",
"href": "/sales-atlas/account?view=mine"
}
]
}
}
]
}
<caos-button variant="secondary">Accounts ⌄</caos-button>
<caos-object-caret id="objectCaret2"></caos-object-caret>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const objectCaret2 = document.getElementById('objectCaret2');
objectCaret2.recents = [
{
"id": "a1",
"label": "Meridian Supply",
"href": "/sales-atlas/account/a1"
},
{
"id": "a2",
"label": "Calder & Finch",
"href": "/sales-atlas/account/a2"
}
];
objectCaret2.views = [
{
"id": "v1",
"label": "All Accounts",
"href": "/sales-atlas/account?view=all"
},
{
"id": "v2",
"label": "My Accounts",
"href": "/sales-atlas/account?view=mine"
}
];

The same menu for an object nobody has opened yet: with no recents the “Recently Viewed” section is not drawn, so the menu is list views alone.

The page around it: The surrounding page plays the tab row again: the button is the caret, and pressing it opens the menu at its rectangle.

{
"id": "example",
"section": "Views only",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary"
},
"children": [
"Orders ⌄"
]
},
{
"id": "object_caret_2",
"type": "component",
"key": "object_caret",
"inputs": {
"recents": [],
"views": [
{
"id": "v1",
"label": "All Orders",
"href": "/sales-atlas/order?view=all"
},
{
"id": "v2",
"label": "Open Orders",
"href": "/sales-atlas/order?view=open"
}
]
}
}
]
}
<caos-button variant="secondary">Orders ⌄</caos-button>
<caos-object-caret id="objectCaret2"></caos-object-caret>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const objectCaret2 = document.getElementById('objectCaret2');
objectCaret2.recents = [];
objectCaret2.views = [
{
"id": "v1",
"label": "All Orders",
"href": "/sales-atlas/order?view=all"
},
{
"id": "v2",
"label": "Open Orders",
"href": "/sales-atlas/order?view=open"
}
];