Accordion
<caos-accordion>
stacked sections, each opened and closed from its own header, so a long page is read a part at a time
May be placed on a record page and a page inside an app.
Inputs
Section titled “Inputs”| Name | Attribute | Description | Type | Default | Required |
|---|---|---|---|---|---|
sections |
property only | The sections, as { value, label, open?, hidden? } objects, in the order they are drawn. value names the section and is the slot its content is placed into; label is the words on its header. The sections marked open start open, and when no section says either way the first one does. A hidden section is left out, with its content. A value that repeats an earlier one is dropped. | json | none declared | Optional |
multiple |
multiple, markup only |
Lets several sections stay open at once. Unset, opening a section closes the one that was open, and when several are marked open only the first of them starts open. | boolean | false | Optional |
remember |
remember, markup only |
A name under which the sections each person opens and closes are kept for them on this browser, so their next visit starts where they left it. Give two accordions the same name only if they are the same accordion. Left unset, nothing is kept and every visit starts as authored. | text | none declared | Optional |
Events
Section titled “Events”| Name | When it fires | What it carries |
|---|---|---|
caos-accordion-toggle |
A section is about to open or close — its header is pressed, or openSection, closeSection or toggleSection is called. Cancelable: calling preventDefault leaves every section as it was. A section closed because another one opened raises nothing of its own. | { value, open } — the section, and the state it is about to move to. |
| Name | What goes in it |
|---|---|
<section value> |
The content of one section: anything placed with slot set to that section’s value. Several pieces may name the same section and are drawn in order. Content naming no section, or a hidden one, is not drawn. |
Styling hooks
Section titled “Styling hooks”| Design token | What it controls |
|---|---|
--caos-color-border |
The hairline between one section and the next. |
--caos-color-text |
The header text, and the chevron of a hovered header. |
--caos-color-text-muted |
The chevron at rest. |
--caos-font |
The typeface of the headers. |
--caos-space-2 |
The gap between the chevron and the label, and so how far content is indented. |
--caos-space-3 |
The space above and below a header, and below an open section’s content. |
--caos-focus-ring |
The ring drawn on a header reached by keyboard. |
--caos-radius-sm |
The corners of that ring. |
Methods
Section titled “Methods”| Name | Description | Arguments |
|---|---|---|
openSection() |
Open a section, exactly as pressing its header does — the same cancelable event fires first. Returns false when nothing changed: the section is unknown, hidden or already open, or the event was cancelled. | value: string |
closeSection() |
Close a section, the same way. Returns false when nothing changed. | value: string |
toggleSection() |
Open a closed section or close an open one. Returns false when nothing changed. | value: string |
Readable state
Section titled “Readable state”| Name | Type | What it tells you |
|---|---|---|
open |
string[] | The values of the sections open now, in the order they are drawn. |
Styling parts
Section titled “Styling parts”| Part | Which piece of it | When it is there |
|---|---|---|
::part(accordion) |
the run of sections | Always |
::part(section) |
one section, its header and its content together | Always |
::part(header) |
the button that opens and closes a section | Always |
::part(label) |
the words on a header | Always |
::part(panel) |
the region a section’s content is drawn in | Always |
When to use it
Section titled “When to use it”A page with more sections than anybody reads at once, where each is worth reaching but few are worth seeing all the time — the record page with eight sections. If a person needs to compare two sections side by side, keep them open as detail sections instead.
What to use instead
Section titled “What to use instead”- DetailSection — There is one block, or a few that have nothing to do with one another; set it collapsible if it should fold.
- TabStrip — Only one face of the subject is worth looking at at a time, and the faces are few enough to name across a row.
Accessibility
Section titled “Accessibility”Each header is a real button carrying aria-expanded, pointing aria-controls at its section, and each section is a region labelled by its header, so a screen reader announces what opens and whether it is open. Arrow Down and Arrow Up move between headers and wrap at the ends; Home and End go to the first and the last. Keys pressed inside a section’s content are left alone. A closed section’s content is hidden, not merely out of sight, so it is out of the tab order and the accessibility tree. The chevron turns toward the reading direction, so it reads correctly right to left. What is left to the author: a label that says what the section holds.
Examples
Section titled “Examples”Sections of a record
Section titled “Sections of a record”The ordinary case: the sections of a record page, one open at a time, the first open because no section says otherwise. Opening another closes it.
{ "id": "example", "section": "Sections of a record", "columns": 1, "items": [ { "id": "accordion_1", "type": "component", "key": "accordion", "inputs": { "sections": [ { "value": "details", "label": "Details" }, { "value": "billing", "label": "Billing" }, { "value": "shipping", "label": "Shipping" } ] }, "children": [ { "id": "key_value_row_2", "type": "component", "key": "key_value_row", "inputs": { "label": "Account", "value": "Northwind Traders" }, "slot": "details" }, { "id": "key_value_row_3", "type": "component", "key": "key_value_row", "inputs": { "label": "Owner", "value": "Dana Ruiz", "no_border": true }, "slot": "details" }, { "id": "key_value_row_4", "type": "component", "key": "key_value_row", "inputs": { "label": "Terms", "value": "Net 30", "no_border": true }, "slot": "billing" }, { "id": "key_value_row_5", "type": "component", "key": "key_value_row", "inputs": { "label": "Method", "value": "Freight", "no_border": true }, "slot": "shipping" } ] } ]}<caos-accordion id="accordion1"> <caos-key-value-row slot="details" label="Account" value="Northwind Traders"></caos-key-value-row> <caos-key-value-row slot="details" label="Owner" value="Dana Ruiz" no-border></caos-key-value-row> <caos-key-value-row slot="billing" label="Terms" value="Net 30" no-border></caos-key-value-row> <caos-key-value-row slot="shipping" label="Method" value="Freight" no-border></caos-key-value-row></caos-accordion>// What an attribute cannot hold, set as a property — the same values the preview is drawn with.const accordion1 = document.getElementById('accordion1');accordion1.sections = [ { "value": "details", "label": "Details" }, { "value": "billing", "label": "Billing" }, { "value": "shipping", "label": "Shipping" }];Several open at once
Section titled “Several open at once”With multiple set, sections open and close independently, and the two the author marked open both start open.
{ "id": "example", "section": "Several open at once", "columns": 1, "items": [ { "id": "accordion_1", "type": "component", "key": "accordion", "inputs": { "multiple": true, "sections": [ { "value": "details", "label": "Details", "open": true }, { "value": "billing", "label": "Billing", "open": true }, { "value": "notes", "label": "Notes" } ] }, "children": [ { "id": "key_value_row_2", "type": "component", "key": "key_value_row", "inputs": { "label": "Account", "value": "Northwind Traders", "no_border": true }, "slot": "details" }, { "id": "key_value_row_3", "type": "component", "key": "key_value_row", "inputs": { "label": "Terms", "value": "Net 30", "no_border": true }, "slot": "billing" }, { "id": "key_value_row_4", "type": "component", "key": "key_value_row", "inputs": { "label": "Last call", "value": "2 Sep 2026", "no_border": true }, "slot": "notes" } ] } ]}<caos-accordion id="accordion1" multiple> <caos-key-value-row slot="details" label="Account" value="Northwind Traders" no-border></caos-key-value-row> <caos-key-value-row slot="billing" label="Terms" value="Net 30" no-border></caos-key-value-row> <caos-key-value-row slot="notes" label="Last call" value="2 Sep 2026" no-border></caos-key-value-row></caos-accordion>// What an attribute cannot hold, set as a property — the same values the preview is drawn with.const accordion1 = document.getElementById('accordion1');accordion1.sections = [ { "value": "details", "label": "Details", "open": true }, { "value": "billing", "label": "Billing", "open": true }, { "value": "notes", "label": "Notes" }];A section left out
Section titled “A section left out”The same sections with one marked hidden: it is not drawn, and neither is what was placed in it.
{ "id": "example", "section": "A section left out", "columns": 1, "items": [ { "id": "accordion_1", "type": "component", "key": "accordion", "inputs": { "sections": [ { "value": "details", "label": "Details" }, { "value": "approvals", "label": "Approvals", "hidden": true }, { "value": "billing", "label": "Billing" } ] }, "children": [ { "id": "key_value_row_2", "type": "component", "key": "key_value_row", "inputs": { "label": "Account", "value": "Northwind Traders", "no_border": true }, "slot": "details" }, { "id": "key_value_row_3", "type": "component", "key": "key_value_row", "inputs": { "label": "Approver", "value": "Not shown", "no_border": true }, "slot": "approvals" }, { "id": "key_value_row_4", "type": "component", "key": "key_value_row", "inputs": { "label": "Terms", "value": "Net 30", "no_border": true }, "slot": "billing" } ] } ]}<caos-accordion id="accordion1"> <caos-key-value-row slot="details" label="Account" value="Northwind Traders" no-border></caos-key-value-row> <caos-key-value-row slot="approvals" label="Approver" value="Not shown" no-border></caos-key-value-row> <caos-key-value-row slot="billing" label="Terms" value="Net 30" no-border></caos-key-value-row></caos-accordion>// What an attribute cannot hold, set as a property — the same values the preview is drawn with.const accordion1 = document.getElementById('accordion1');accordion1.sections = [ { "value": "details", "label": "Details" }, { "value": "approvals", "label": "Approvals", "hidden": true }, { "value": "billing", "label": "Billing" }];Sections inside a section
Section titled “Sections inside a section”An accordion placed in one of another accordion’s sections. The same chevron marks every level, and the inner one is indented by that chevron alone.
{ "id": "example", "section": "Sections inside a section", "columns": 1, "items": [ { "id": "accordion_1", "type": "component", "key": "accordion", "inputs": { "sections": [ { "value": "addresses", "label": "Addresses" }, { "value": "terms", "label": "Terms" } ] }, "children": [ { "id": "accordion_2", "type": "component", "key": "accordion", "inputs": { "sections": [ { "value": "billing", "label": "Billing address" }, { "value": "shipping", "label": "Shipping address" } ] }, "slot": "addresses", "children": [ { "id": "key_value_row_3", "type": "component", "key": "key_value_row", "inputs": { "label": "City", "value": "Tacoma", "no_border": true }, "slot": "billing" }, { "id": "key_value_row_4", "type": "component", "key": "key_value_row", "inputs": { "label": "City", "value": "Spokane", "no_border": true }, "slot": "shipping" } ] }, { "id": "key_value_row_5", "type": "component", "key": "key_value_row", "inputs": { "label": "Payment", "value": "Net 30", "no_border": true }, "slot": "terms" } ] } ]}<caos-accordion id="accordion1"> <caos-accordion id="accordion1accordion1" slot="addresses"> <caos-key-value-row slot="billing" label="City" value="Tacoma" no-border></caos-key-value-row> <caos-key-value-row slot="shipping" label="City" value="Spokane" no-border></caos-key-value-row> </caos-accordion> <caos-key-value-row slot="terms" label="Payment" value="Net 30" no-border></caos-key-value-row></caos-accordion>// What an attribute cannot hold, set as a property — the same values the preview is drawn with.const accordion1 = document.getElementById('accordion1');const accordion1accordion1 = document.getElementById('accordion1accordion1');accordion1.sections = [ { "value": "addresses", "label": "Addresses" }, { "value": "terms", "label": "Terms" }];accordion1accordion1.sections = [ { "value": "billing", "label": "Billing address" }, { "value": "shipping", "label": "Shipping address" }];Inside a section’s card
Section titled “Inside a section’s card”An accordion inside a detail section, which brings the card. The accordion adds no spacing of its own, so its headers line up with the section’s content.
{ "id": "example", "section": "Inside a section’s card", "columns": 1, "items": [ { "id": "detail_section_1", "type": "component", "key": "detail_section", "inputs": { "heading": "Account" }, "children": [ { "id": "accordion_2", "type": "component", "key": "accordion", "inputs": { "sections": [ { "value": "details", "label": "Details" }, { "value": "billing", "label": "Billing" } ] }, "children": [ { "id": "key_value_row_3", "type": "component", "key": "key_value_row", "inputs": { "label": "Owner", "value": "Dana Ruiz", "no_border": true }, "slot": "details" }, { "id": "key_value_row_4", "type": "component", "key": "key_value_row", "inputs": { "label": "Terms", "value": "Net 30", "no_border": true }, "slot": "billing" } ] } ] } ]}<caos-detail-section heading="Account"> <caos-accordion id="detailSection1accordion1"> <caos-key-value-row slot="details" label="Owner" value="Dana Ruiz" no-border></caos-key-value-row> <caos-key-value-row slot="billing" label="Terms" value="Net 30" no-border></caos-key-value-row> </caos-accordion></caos-detail-section>// What an attribute cannot hold, set as a property — the same values the preview is drawn with.const detailSection1accordion1 = document.getElementById('detailSection1accordion1');detailSection1accordion1.sections = [ { "value": "details", "label": "Details" }, { "value": "billing", "label": "Billing" }];