Skip to content

NavGadget

<caos-nav-gadget>

the Customize Navigation control at the far end of the tab row

May be placed on a seam in the workspace frame.

Name Attribute Description Type Default Required
items property only The navigation as it stands, as { id, label, href, active? }, in display order. The first list set is also remembered as the default that “Reset to Default” restores. json none declared Optional
available property only The items a person may add, as { id, label, href }. Optional — a tab that is hidden is moved into this list, so it can always be added back even if nothing was supplied here. json none declared Optional
appLabel app-label, markup only The name of the app whose navigation is being edited, woven into the popup’s subtitle. text this app Optional
Name When it fires What it carries
gadget-nav-change After any reorder, hide or add — including the one that follows a reset. { items } — the whole new VISIBLE navigation, in order.
gadget-nav-reset “Reset to Default” was chosen. A gadget-nav-change carrying the restored list follows it. nothing

Nothing goes inside this piece.

Design token What it controls
--caos-color-accent The sliders glyph, the active row’s inset bar, and the “+ Add” text.
--caos-color-accent-fill The Done button’s fill.
--caos-color-accent-fill-hover The Done button’s fill under the pointer.
--caos-color-accent-contrast The label on the Done button. White by default; a brand with a pale accent sets a darker ink here.
--caos-color-border The trigger’s outline, the popup’s outline, and the rules under its head and over its footer.
--caos-color-border-strong The trigger’s outline on hover, and a footer button’s on hover.
--caos-color-surface The popup’s background, its sticky footer, and the trigger’s fill on hover.
--caos-color-surface-2 The trigger’s resting fill and a row’s hover fill.
--caos-color-bg The fill of the “Search items to add…” box.
--caos-color-text The title, the row labels, and the footer buttons.
--caos-color-text-muted The subtitle, the section labels, the move/hide glyphs, and the no-matches line.
--caos-color-text-ghost The search box’s placeholder.
--caos-focus-ring The ring on the trigger and on every control inside the popup.
--caos-font The typeface of the popup and its buttons.
--caos-font-mono The section labels and the “+ Add” buttons.
--caos-radius The popup’s corner radius.
--caos-radius-sm The corner radius of the trigger, the small buttons and the search box.
--caos-shadow-float The shadow that lifts the popup off the page.

Nothing else drives this piece by calling it.

Nothing on this piece can be read back.

This piece exposes none of its insides to a stylesheet.

Only as the workspace frame’s customize-navigation control. It changes what ONE person sees in their own tab row; it is not how an administrator configures an app’s tabs for everybody.

  • WorkspaceTabs — You want the tab row itself rather than the control that edits it.
  • AppLauncher — Somebody is moving to another app rather than reshaping the row of the one they are in.
  • OverflowMenu — What is behind the trigger is a list of actions to run, not a list to reorder and keep.

The trigger is a real button carrying aria-haspopup="dialog" and an aria-expanded kept in step with the popup, and the popup is a role="dialog" labelled “Customize Navigation”. Every move, hide and add control is a real button with its own accessible name (“Move up”, “Hide”, “Add Orders”), the ones that cannot act are genuinely disabled rather than merely faded, the search box is labelled, and the glyphs are hidden from assistive technology. Escape and a click outside dismiss it. Focus moves into the popup when it opens, Tab and Shift+Tab stay inside it and wrap at either end, and Escape or Done hands focus back to the trigger; a click outside leaves focus where the click put it. What is left to the author: a reorder is announced only by the row order changing, so nothing is said out loud when an item moves.

The trigger at the end of a row; pressing it opens the real popup, where the tabs can be reordered, hidden and added back.

{
"id": "example",
"section": "Customize Navigation",
"columns": 1,
"items": [
{
"id": "nav_gadget_1",
"type": "component",
"key": "nav_gadget",
"inputs": {
"app_label": "Sales Atlas",
"items": [
{
"id": "home",
"label": "Home",
"href": "/sales-atlas",
"active": true
},
{
"id": "account",
"label": "Accounts",
"href": "/sales-atlas/account"
},
{
"id": "invoice",
"label": "Invoices",
"href": "/sales-atlas/invoice"
}
],
"available": [
{
"id": "order",
"label": "Orders",
"href": "/sales-atlas/order"
},
{
"id": "contact",
"label": "Contacts",
"href": "/sales-atlas/contact"
}
]
}
}
]
}
<caos-nav-gadget id="navGadget1" app-label="Sales Atlas"></caos-nav-gadget>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const navGadget1 = document.getElementById('navGadget1');
navGadget1.items = [
{
"id": "home",
"label": "Home",
"href": "/sales-atlas",
"active": true
},
{
"id": "account",
"label": "Accounts",
"href": "/sales-atlas/account"
},
{
"id": "invoice",
"label": "Invoices",
"href": "/sales-atlas/invoice"
}
];
navGadget1.available = [
{
"id": "order",
"label": "Orders",
"href": "/sales-atlas/order"
},
{
"id": "contact",
"label": "Contacts",
"href": "/sales-atlas/contact"
}
];