Skip to content

AppLauncher

<caos-app-launcher>

the leading control that lists the apps a person may open

May be placed on a seam in the workspace frame.

Name Attribute Description Type Default Required
apps property only The apps to list, as { key, label, icon?, brand?, destinationCount, children? }. icon names a glyph from the shared vocabulary and is DRAWN; a name outside the vocabulary is printed as raw text instead, so an app from somebody else’s package is never blank. children are the app’s objects, listed indented beneath it. Left unset, the panel reads “No apps yet.” json none declared Optional
activeAppKey active-app-key, markup only The key of the app currently open. Its row in the panel takes the accent bar, the tinted fill and the CURRENT marker, and the button’s accessible name names it. Unset ⇒ no row is marked and the button is just “App Launcher”. text none declared Optional
Name When it fires What it carries
launcher-navigate An app row, or one of an app’s indented object rows, was chosen. The panel closes itself; going anywhere is the host’s half. { key } for an app; { key, href } for one of its objects.
launcher-get-more-apps The persistent “Get more apps” row at the foot of the panel was chosen. The panel closes itself; what opens is the host’s half — the component knows nothing about packages or installs. Nothing. The choice is the whole message.

Nothing goes inside this piece.

Design token What it controls
--caos-color-accent The waffle glyph, and the current app row’s inset bar, icon and CURRENT marker.
--caos-color-border The trigger’s outline, the panel’s outline, and the rules inside the panel.
--caos-color-border-strong The trigger’s outline while the pointer is over it.
--caos-color-surface The panel’s background, and the trigger’s fill on hover.
--caos-color-surface-2 The trigger’s resting fill, a row’s hover fill, and the current app row’s tint.
--caos-color-bg The fill of the search box inside the panel.
--caos-color-text The app labels, and what is typed into the search box.
--caos-color-text-muted The section label, an app’s glyph, the child bullets, and the no-matches line.
--caos-color-text-ghost The search box’s placeholder.
--caos-focus-ring The ring on the trigger and on a row reached by keyboard.
--caos-font The typeface inside the panel.
--caos-font-mono The “Apps” section label and the CURRENT marker.
--caos-radius-sm The trigger’s corner radius.
--caos-space-5 The inset between the start of the tab row and the trigger.

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 app switcher. If what you want is a menu of choices somewhere on a page, this is not it — this piece is the one place a person leaves the app they are in.

  • WorkspaceTabs — Somebody is moving between destinations inside the app they are already in.
  • NavGadget — Somebody wants to change which tabs their own row shows, rather than move to another app.
  • OverflowMenu — What is behind the trigger is a list of ACTIONS on a record or a row, not a list of places.

The trigger is a real button carrying aria-haspopup="menu" and an aria-expanded kept in step with the panel, and its accessible name names the current app. The panel is a role="menu" labelled “Apps” whose rows are role="menuitem", the current app’s row is marked aria-current, the search box is labelled, and the glyphs are hidden from assistive technology. Escape and a click outside both dismiss it, and focus moves to the search box when it opens. While it is open, Tab and Shift+Tab stay inside the panel and wrap at either end; Escape or choosing an app hands focus back to the trigger, and a click outside leaves focus where the click put it. What is left to the author: an app’s LABEL is the only thing telling one row from another.

The button as it sits at the head of the tab row; pressing it opens the real panel, with the current app marked and its objects listed beneath it.

{
"id": "example",
"section": "The app list",
"columns": 1,
"items": [
{
"id": "app_launcher_1",
"type": "component",
"key": "app_launcher",
"inputs": {
"active_app_key": "sales-atlas",
"apps": [
{
"key": "sales-atlas",
"label": "Sales Atlas",
"icon": "building-2",
"destinationCount": 3,
"children": [
{
"key": "account",
"label": "Accounts",
"href": "/sales-atlas/account"
},
{
"key": "contact",
"label": "Contacts",
"href": "/sales-atlas/contact"
},
{
"key": "order",
"label": "Orders",
"href": "/sales-atlas/order"
}
]
},
{
"key": "setup",
"label": "Setup",
"icon": "settings",
"destinationCount": 12
},
{
"key": "atlantis-ai",
"label": "Atlantis AI",
"icon": "sparkles",
"destinationCount": 1
}
]
}
}
]
}
<caos-app-launcher id="appLauncher1" active-app-key="sales-atlas"></caos-app-launcher>
// What an attribute cannot hold, set as a property — the same values the preview is drawn with.
const appLauncher1 = document.getElementById('appLauncher1');
appLauncher1.apps = [
{
"key": "sales-atlas",
"label": "Sales Atlas",
"icon": "building-2",
"destinationCount": 3,
"children": [
{
"key": "account",
"label": "Accounts",
"href": "/sales-atlas/account"
},
{
"key": "contact",
"label": "Contacts",
"href": "/sales-atlas/contact"
},
{
"key": "order",
"label": "Orders",
"href": "/sales-atlas/order"
}
]
},
{
"key": "setup",
"label": "Setup",
"icon": "settings",
"destinationCount": 12
},
{
"key": "atlantis-ai",
"label": "Atlantis AI",
"icon": "sparkles",
"destinationCount": 1
}
];