📘 Theory

Four families of solutions

Before choosing a style, choose the opening mechanism.

1

The ten snippets fall into four families: pure CSS, native HTML behaviors, minimal JavaScript for state and richer JavaScript for animation.

2

Pure CSS is attractive for simple menus and quick demos, but it can become rigid when you need outside-click closing, dynamic height coordination or multiple synchronized states.

3

Native APIs such as `details`, `dialog` and `popover` reduce code and solve part of the accessibility model for you. They are especially compelling when your browser support target makes them viable.

Patterns with no JavaScript or almost none

These are easier to maintain when navigation does not require complex logic.

This group includes the checkbox hack, `:has()`, `details` and menu patterns that simply reflow links with Grid instead of collapsing into a burger panel.

Their main strength is clarity: the visual state lives in HTML and CSS, so the component is easier to inspect, test and port between projects.

The downside is flexibility. Once the interaction needs richer behavior, the pattern can become awkward to extend without bringing in JavaScript anyway.

  • Checkbox hack and `:has()` work well when the state is basically open or closed.
  • `details` and `summary` are especially useful for simple disclosure-style navigation.
  • A responsive Grid layout can avoid the burger pattern altogether if the menu can reflow cleanly.

Patterns with minimal or expressive JavaScript

Use them when the interaction adds real value, not out of habit.

1

The snippets based on `aria-expanded`, `classList` and measured heights show a practical middle ground: small JavaScript that keeps attributes, visual state and accessibility aligned.

2

WAAPI goes further by defining animation keyframes in JavaScript itself, which gives you tighter control over timing, stagger and spatial rhythm than a simple class toggle.

3

The professional rule is that state should still stay understandable. If neither the user nor the developer can tell what is opening the menu and why, the pattern will not scale well.

How to choose the right pattern

The decision should come from constraints, not from aesthetics alone.

1

Choose pure CSS if...

The menu is short, the interaction is binary and you want a component that is easy to port or teach.

2

Choose a native API if...

You want focus, Escape handling or outside-click closing with less custom code and your browser support allows it.

3

Choose minimal JS if...

You need to sync ARIA attributes, measure real panel heights or lock body scroll without introducing a heavy architecture.

4

Choose WAAPI if...

Animation is part of the product language and needs more control than `classList` plus `transition` can provide.

🧪 Learn by doing

Example Demo: brutalist menu with the checkbox hack A pure CSS approach with a strong visual style and a very easy-to-inspect state model.
Example Demo: glassmorphism menu with measured height The JavaScript reads `scrollHeight` and uses it as the real panel height, which is cleaner than relying on a fake `max-height` trick.
Example Demo: terminal menu with `details` and `summary` A strong native reference for learning disclosure behavior without JavaScript.
Example Demo: editorial menu with adaptive Grid A case where no burger is needed because the layout itself responds cleanly.
Example Demo: cyberpunk menu with WAAPI Uses `element.animate()` with staggered links, which is a good example of when programmatic animation really adds value.
Example Demo: swiss menu with `@starting-style` Shows how to animate from `display: none` with modern CSS using `@starting-style` and `transition-behavior: allow-discrete`.
Example Demo: art deco menu with the Popover API A strong example of using a native API to open and close a panel without custom controller logic.
Example Demo: organic full-screen menu with `dialog` A full-screen menu that benefits from native focus handling and Escape behavior.
Example Demo: industrial menu with `aria-expanded` One of the most professional patterns for keeping accessibility and visual state connected to the same source of truth.
Example Demo: playful menu with `:has()` The parent reacts to the checkbox state through `:has()`, which is more flexible than older sibling-combinator patterns.

🏁 Challenges

Challenge Challenge: connect `aria-expanded` to the mobile panel Synchronize the ARIA state of the button with the visual opening of the menu panel.

What is this?

I'm Cristian Eslava and I sometimes build websites so both you and I can learn and experiment. culTest

I made this in February 2026 to make learning easier for my students. The idea is to learn web development by practicing and to keep expanding the project with new topics, tests and challenges.

It draws inspiration from MDN, W3Schools, CodePen, Manz and many other web development references. I wanted to combine useful theory, runnable examples, challenges and the testing system I had already built for culTest. culTest

If you liked it, if you didn't, or if you want to get in touch, write to me at cristianeslava@gmail.com