Repository navigation
Defer tabs until a native accessible HTML primitive is available #61
Description
Source
Upstream: picocss/pico discussion #608 (11 upvotes, one of the higher-engagement Ideas threads), found during a sweep of picocss/pico's Discussions for items not yet covered by cirth's M5 audit.
Problem
Tabs are a common UI pattern with no equivalent in cirth today. The upstream proposal combines <details> with role="tablist"/role="tab"/role="tabpanel":
<div role="tablist">
<details role="tab" name="my-tabs" open>
<summary>First</summary>
<div role="tabpanel">First tab content</div>
</details>
...
</div>Real accessibility risk flagged in the same thread, not to be glossed over: <details>'s only permitted implicit/explicit ARIA role is group — role="tab" on a <details> element is not sanctioned by the HTML-ARIA mapping spec, so this pattern may fail ARIA validation and could confuse assistive tech despite "working" visually. This needs a real decision, not a straight port of the upstream proposal.
Ask
Evaluate whether a tabs component is worth shipping, and if so, find a spec-clean implementation:
- Is there a construction using native/permitted roles that still avoids JS (e.g., radio-button-driven tabs with
appearance: none, which several other CSS-only tab implementations use, at the cost of "nastier" markup per the same thread)? - Or does this only become clean once a future platform primitive lands (native
<tabs>/<tab-group>proposals exist in various stages)? - If no clean JS-free/spec-clean path exists today, document that explicitly as the outcome rather than leaving the idea open indefinitely.
Acceptance
- A written decision: ship (with the spec-clean markup used), or explicitly deferred/rejected with the reasoning recorded.
- If shipped: docs page, live demo, a11y-audited (axe) like every other component.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Projects
- StatusShow more project fields✅ Done
Activity
ricpastori commentedon Aug 15, 2026
Proposed decision
I recommend deferring this component until HTML provides a native tabs primitive with interoperable browser and accessibility support.
At the moment, Cirth cannot implement a true tabs component that is simultaneously:
This is not primarily a styling limitation. The missing part is native interaction and state management.
Why the
<details>proposal cannot be usedThe proposed markup assigns
role="tab"to<details>:This is not conforming HTML/ARIA.
<details>has an implicitgrouprole and cannot be changed totab. A<summary>that belongs to its parent<details>cannot be assigned an alternative role either.Reference: ARIA in HTML
The native interaction also remains that of a disclosure:
<summary>;EnterorSpacetoggles the disclosure;Preventing the active summary from closing with:
would only block pointer activation. Keyboard activation could still behave differently, creating inconsistent input behaviour.
Even if the elements were visually arranged like tabs, assistive technology would still encounter a group of disclosures. Presenting one interaction model visually while exposing another programmatically would be misleading.
<details name>remains useful for an exclusive disclosure or accordion pattern, but it should not be presented as tabs.Why a radio-based implementation is not a replacement
Radio buttons can maintain a mutually exclusive
checkedstate without JavaScript, and browsers provide native keyboard interaction for a radio group.However, that produces a radio-based view selector, not an ARIA tabs widget.
A CSS-only implementation cannot keep all required tabs state synchronized:
aria-selectedon the active tab;tabindex="0"on the active tab;tabindex="-1"on inactive tabs;tabpanel;HomeandEndbehaviour;Keeping the controls exposed as radio buttons would be semantically honest, but it would be a different component. Reassigning tab roles would promise an interaction model that is not actually implemented.
Hiding the radio inputs also introduces further risks. If they are removed from the accessibility tree or keyboard navigation, the remaining labels do not become accessible tab controls automatically.
Why
:targetis not a replacementA link-based implementation using fragments and
:targetwould provide same-page navigation:This can be an accessible navigation pattern, but it is not a tabs widget:
It should therefore remain a same-page navigation pattern rather than being described as tabs.
Requirements of a real tabs component
The established tabs pattern requires:
tablist;tabfor eachtabpanel;aria-controlsandaria-labelledbyassociations;aria-selected;tabindex;EnterorSpaceactivation when manual activation is used;Reference: WAI-ARIA Tabs Pattern
ARIA roles only expose semantics. Browsers do not add the required keyboard behaviour when
role="tab"is declared. Authors must implement that behaviour.Reference: WAI-ARIA — Developing a Keyboard Interface
CSS can select and present a state, but it cannot manage focus or update the corresponding ARIA attributes. Therefore, correct ARIA tabs currently require script.
Could Cirth provide styles for externally scripted tabs?
Technically, Cirth could style conforming application-provided markup:
This would keep the Cirth package itself CSS-only, while requiring the consuming application to provide the behaviour.
However, it would not satisfy the original goal of a component that works without JavaScript. It would also make the component appear functional based on its styling even when the required script is missing or incomplete.
Unless Cirth explicitly decides that “CSS-only” means only “Cirth does not bundle JavaScript”, rather than “the documented component works without JavaScript”, I do not think this should be shipped as a core component.
Progressive enhancement considerations
A safely enhanced tabs implementation should start with every section available in document order. JavaScript would then:
If the script fails, all content remains visible.
This is a valid application architecture, but it cannot be completed by Cirth CSS alone.
Native platform status
Open UI has been researching a native tabs control, including semantics, focus management, keyboard behaviour and a progressive fallback model.
Reference: Open UI Tabs research
Until such a primitive is standardized, implemented and sufficiently interoperable, every CSS-only workaround would either expose incorrect semantics or implement only part of the required behaviour.
Recommended resolution
Defer the tabs component.
The issue can document the decision as follows:
<details name>is a disclosure/accordion pattern, not tabs;:targetimplements navigation, not tabs;This avoids shipping a component that looks correct while exposing incomplete or misleading behaviour to keyboard and assistive-technology users.
[-]Evaluate a tabs component (upstream pico discussion #608)[/-][+]Defer tabs until a native accessible HTML primitive is available[/+]ricpastori commentedon Oct 14, 2026
Audit del 14 ottobre 2026: chiudo questa issue come non pianificata. Il titolo e la decisione già registrata stabiliscono il rinvio finché HTML non offrirà una primitiva tabs nativa, interoperabile e accessibile. Il sorgente corrente non espone una API tabs; l’issue potrà essere riaperta se cambia lo stato della piattaforma.