Skip to content

Overlay

<caos-overlay>

the one scrim-and-panel shell behind every modal and drawer

Nowhere yet — this piece is not offered to a page.

Name Attribute Description Type Default Required
label label, markup only The accessible name of the dialog. It is what a screen reader announces on entering the panel, so it should say which dialog this is rather than what it contains. text none declared Optional
placement placement, markup only Where the panel sits: center, a modal floating near the top of the page, or end, a full-height drawer flush against the right-hand edge. Everything else about the two is identical. text — one of center, end center Optional
Name When it fires What it carries
caos-overlay-close The scrim is clicked or Escape is pressed. It is a REQUEST — the overlay does not remove itself, and the event is cancelable, so a host with unsaved changes can prevent it and ask. nothing
Name What goes in it
the default slot The panel body. It gets no padding from the shell, so whatever goes in brings its own — a padded head with a full-bleed divider under it is the shape every caller uses.
Design token What it controls
--caos-overlay-width How wide the panel is: the max width of a centred modal (760px by default) and the fixed width of a drawer (420px). Set by the caller per dialog — a two-column record form needs more than a confirmation does.
--caos-overlay-scrim The dimming behind the panel. Defined on the element itself with a default of rgba(0, 0, 0, 0.6) — a token that names this component rather than a platform axis, which is recorded here rather than left buried in the stylesheet.
--caos-color-surface The panel fill.
--caos-color-border-strong The panel edge.
--caos-shadow-float The one elevation reserved for pieces that float.
--caos-radius-lg The corner radius of a centred modal. A drawer has none on its flush edge.
--caos-space-4 The gap between a centred modal and the edge of the screen.
Name Description Arguments
requestClose() Raise the close request from code, exactly as the scrim and Escape do — for a Cancel button inside the panel, so one path decides what closing means. takes none
alertDialog() Say something and wait for it to be acknowledged. One button, nothing to read back: the button, the scrim and Escape all mean the same thing. Takes { message, heading, confirmLabel }. This and the two below are CALLS against this one overlay rather than small dialog components of their own — they are the same dialog with different footers, so they share the scrim, the focus trap, the Escape behaviour and the dialog role instead of each keeping a copy. options: CaosDialogOptions
confirmDialog() Ask before going ahead. Resolves true only if the committing button was the answer — the scrim and Escape are a no, because a dialog somebody dismissed is not a dialog somebody agreed to. Told that committing is destructive, the committing button takes the destructive colour and nothing else about the dialog changes. options: CaosDialogOptions
promptDialog() Ask for something and read it back. Resolves the text as typed, or null if the dialog was cancelled or dismissed — which is how a caller tells “they typed nothing” from “they said no”, two answers an empty string cannot keep apart. The field is focused first, because it is what the dialog is for. options: CaosPromptOptions

Nothing on this piece can be read back.

Part Which piece of it When it is there
::part(scrim) the dimmed backdrop, which is also the click-to-close target Always
::part(panel) the floating panel Always

Something has to be dealt with in front of the page, rather than on it: a form for a new record, a confirmation, a picker, a detail panel that arrives from the side. Reach for this one whether it ends up centred or on the edge — it is the same shell either way.

  • Inspector — The panel belongs BESIDE the work rather than over it, and the page behind it stays usable while somebody edits the properties of what they have selected.
  • SplitView — The second pane is part of the surface — a list on the left, the record you are reading on the right.
  • OverflowMenu — What opens is a short list of actions off a trigger, not a panel of content.

The panel is a role=“dialog” with aria-modal, named by the label attribute. On mount it moves focus inside (deferred a frame so slotted content has rendered its controls), traps Tab within the panel — piercing slotted custom elements, so a button whose real control lives in its own shadow root is still in the ring — and returns focus to whatever opened it when it is unmounted. The scrim is a real button with an accessible name, and Escape does the same thing it does. What is left to the author: set label, or the dialog has no name; and actually unmount on close, because the focus return happens on disconnect.

The shell with its default placement: a dialog floating near the top of the page, scrim behind it, capped at the width its caller gives it.

The page around it: sets the panel width, the way the create form and the package picker each set theirs, and unmounts the overlay when it reports a close — presence in the DOM is what open means

{
"id": "example",
"section": "As a centred modal",
"columns": 1,
"items": [
{
"id": "overlay_1",
"type": "component",
"key": "overlay",
"inputs": {
"label": "Order details"
},
"children": [
{
"id": "inspector_2",
"type": "component",
"key": "inspector",
"inputs": {
"heading": "ORD-4471"
},
"children": [
{
"id": "key_value_row_3",
"type": "component",
"key": "key_value_row",
"inputs": {
"label": "Account",
"value": "Meridian Supply"
}
},
{
"id": "key_value_row_4",
"type": "component",
"key": "key_value_row",
"inputs": {
"label": "Total",
"value": "$12,400"
}
}
]
}
]
}
]
}
<caos-overlay label="Order details">
<caos-inspector heading="ORD-4471">
<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>
</caos-overlay>

The same declaration with placement set to end: full height, flush against the right edge, no rounded corners on the side it is flush with — one input apart from the modal above.

The page around it: sets the drawer width and unmounts the overlay when it reports a close

{
"id": "example",
"section": "As a right-hand drawer",
"columns": 1,
"items": [
{
"id": "overlay_1",
"type": "component",
"key": "overlay",
"inputs": {
"label": "Order details",
"placement": "end"
},
"children": [
{
"id": "inspector_2",
"type": "component",
"key": "inspector",
"inputs": {
"heading": "ORD-4471"
},
"children": [
{
"id": "key_value_row_3",
"type": "component",
"key": "key_value_row",
"inputs": {
"label": "Account",
"value": "Meridian Supply"
}
},
{
"id": "key_value_row_4",
"type": "component",
"key": "key_value_row",
"inputs": {
"label": "Total",
"value": "$12,400"
}
}
]
}
]
}
]
}
<caos-overlay label="Order details" placement="end">
<caos-inspector heading="ORD-4471">
<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>
</caos-overlay>