Collapse
A disclosure hides content that most people do not need, and it is worth having only when that is actually true. The default implementation is <details> and <summary>: the browser gives you the state, the keyboard behaviour, the semantics and — importantly — in-page find, which every hand-rolled accordion breaks.
Disclosure
Independent items, any number open at once. This is the default and covers most cases.
How is the overall rating calculated?
The overall figure is the mean of the seven category scores an athlete gave, weighted equally. It is not a weighted average of star counts, and organisers cannot change the weighting.
Can an organiser remove a review?
No. An organiser can reply to a review and can report one that breaks the guidelines, which sends it to moderation. Removal is a moderation decision, never an organiser one.
Why does this event say “unverified”?
It was added by an athlete rather than claimed by its organiser. It is fully readable and ratable, but it is excluded from regional rankings until someone claims it.
Accordion
One open at a time. Justified only when the sections are long enough that comparing two is not something anyone would want — which is rarer than it sounds. If a user might want to read two panels side by side, the accordion is fighting them.
Communication
What the event told you before the day, on the day and after it — the entry emails, the start-line briefing, and whether the published schedule matched what happened.
Provisions
What was on the support tables, how far apart they were, and whether anything was left for the final finishers.
Assistance
Marshals, medical cover, bag drop and lost property — and what actually happened when someone needed help.
The name attribute on <details> gives exclusive accordion behaviour with no JavaScript at all. Where it is unsupported, every panel simply opens independently — the content stays reachable, which is the correct way for this to degrade.
Specification
| Property | Value | Why |
|---|---|---|
| Element | <details> / <summary> | State, keyboard and find-in-page for free |
| Trigger height | 52px minimum | Comfortably past the 44px floor for a full-width row |
| Trigger type | --text-ui, weight 500, primary ink | It is a heading and a control at once |
| Divider | 1px hairline between items | The system separates planes with a line |
| Icon | chevron-down closed, chevron-up open | Swapped, not rotated — see below |
| Icon position | Trailing | The label starts at the same x as the body text below it |
| Motion | Colour only on the trigger | Height animation is the single biggest jank source in a list |
| Body | Indented to the label, --text-base | The panel belongs to the trigger, visibly |
Why the chevron does not rotate. Motion allows transform in exactly two places — the bottom sheet and the spinner. A rotating chevron is a third, and it buys nothing a swapped icon does not: the open state is already unambiguous from the panel below it.
Structure
<!-- Default: independent disclosures -->
<details class="collapse">
<summary>
<span class="collapse__title">How is the overall rating calculated?</span>
<span class="collapse__icon" aria-hidden="true"><!-- lucide:chevron-down --></span>
</summary>
<div class="collapse__body"><p>The overall figure is the mean of …</p></div>
</details>
<!-- Accordion: a shared name makes them exclusive, no JS -->
<details class="collapse" name="categories">…</details>
<details class="collapse" name="categories">…</details>If you must hand-roll it — because the trigger has to sit outside the panel — the button carries aria-expanded and aria-controls, the panel carries the referenced id, and the panel is hidden with the hidden attribute rather than height: 0, so find-in-page and Tab both skip it.
Rules
- Never collapse something people need. Price, required steps, error messages, the terms someone is agreeing to, and anything that changes a decision. A disclosure is for depth, not for tidiness.
- The trigger states the answer's subject, not its existence. “How is the overall rating calculated?” — not “More information”.
- Do not open on hover. It fires on the way to somewhere else, and there is no hover on a phone.
- Do not nest disclosures. Two levels of hiding means the second level is never found. Nested depth is a sign the page needs restructuring.
- An open panel must survive a re-render. Collapsing everything when a filter changes discards the user's place.
- Deep links open their target. If a panel is addressable, arriving at its URL must open it and move focus to the trigger.
theme.css.