HuntExams Academy logo
HTML/CSSAdvanced#css#layout-puzzle

How do you build a CSS-only accordion or tab component?

Answer

Use the :checked pseudo-class on hidden radio/checkbox inputs paired with sibling combinators and labels acting as clickable triggers, toggling visibility of the associated content panel with the ~ or + combinator — no JavaScript needed for basic cases.

Example

<input type="checkbox" id="toggle1" hidden>
<label for="toggle1">Section 1</label>
<div class="panel">Content</div>

<style>
.panel { max-height: 0; overflow: hidden; transition: max-height 0.3s; }
#toggle1:checked ~ .panel { max-height: 200px; }
</style>

Detailed explanation

A CSS-only accordion or tab-like component stores its open or selected state in native form controls and uses the :checked pseudo-class to change panel styles. A label linked through for="toggle1" activates the input with id="toggle1". Checkboxes let accordion sections open independently and close again; radio buttons sharing a name allow only one selection within that group. For tab-like layouts, mark one radio checked initially so a panel appears on page load. This approach handles basic disclosure without JavaScript because the browser already manages the controls’ checked state.

The HTML structure determines which CSS selectors work. With an input followed by its label and panel, input:checked + label + .panel targets that specific panel. The general sibling combinator, ~, matches later siblings under the same parent, not descendants or preceding elements. For example, .panel { display: none; } and input:checked + label + .panel { display: block; } provide straightforward switching. Wrap each accordion item separately or use precise selectors: a broad input:checked ~ .panel rule can accidentally reveal multiple later panels. The checked state can also style the associated label to indicate selection.

Accessibility is the main limitation of the supplied example. The hidden attribute removes the input from keyboard navigation and the accessibility tree, while a label is not normally keyboard-focusable. Instead, use a visually hidden technique that preserves input focusability, and expose a visible focus indicator on its label with input:focus-visible + label. Also, max-height: 0 with overflow: hidden merely clips content; it can leave links keyboard-focusable. display: none removes closed panels from layout and accessibility exposure, though a basic display switch does not provide a smooth height transition.

For production accordions, prefer native details and summary when their behaviour fits. A fixed max-height animation can clip long content and produce uneven timing. CSS-only radio interfaces are not complete accessible tab widgets: proper tabs require appropriate roles, synchronised ARIA state, and tab-specific keyboard interaction, usually implemented with JavaScript. Interviewers value both the selector technique and recognition of these limitations.

Key points to remember

  • Use checkboxes for independent toggles and same-name radios for mutually exclusive selection.
  • Connect every label to a unique input ID using its for attribute.
  • Use + for adjacent siblings and ~ for later siblings sharing the same parent.
  • Preserve keyboard access and show visible focus; do not use hidden on interactive inputs.
  • Prefer details/summary for native disclosure and JavaScript for complete accessible tab behaviour.

Common mistakes candidates make

  • Using a broad ~ selector that reveals unintended panels instead of scoping each item.
  • Assuming clipped content is inaccessible or that labels make hidden inputs keyboard-operable.
  • Treating a fixed max-height as content-independent or presenting radio-based switching as a complete accessible tabs implementation.

Likely follow-up questions

Can a radio-based accordion close every section?

Not by activating the selected radio again; native radios remain selected. Use checkboxes for independently collapsible sections, or details elements for native disclosure.

Why is max-height: 200px fragile?

Content taller than 200px will be clipped, especially after text resizing or localisation. The visible animation duration also depends on the actual content height relative to that limit.

Why might accessible tabs still need JavaScript?

A tab widget needs coordinated focus, selection state, panel relationships, and keyboard behaviour such as arrow-key navigation. CSS cannot dynamically update aria-selected attributes, and native radio semantics do not automatically become tab semantics.

Interview tip: Explain the state, label association, and sibling selector first, then distinguish a CSS-only demo from an accessible production component.

Related Interview Questions

1
HTML/CSSAdvanced#css#grid

What is the 'holy grail' layout and how is it built with Grid?

Open
2
HTML/CSSAdvanced#css#units

What is the difference between relative units vw/vh and %?

Open
3
HTML/CSSBeginner#css#box-model

What is the box-sizing property and why is border-box generally preferred?

Open