Skip to content
Nana UI

Interaction states, responsive polish & a smoother docs experience

· Engineering

This release is about the details you feel rather than see on a feature list: how every control responds to a press, a keyboard, or a touch — and how the docs themselves behave across screens. Hover is only one interaction state; a professional component treats pointer, keyboard, and touch as first-class.

We audited all 63 components against the full interaction hierarchy — not just hover. The foundation was already strong (disabled, focus-visible, keyboard, reflected state, reduced-motion, forced-colors were broadly covered), so this pass closed the real gaps:

  • Touch-hover guard. Every visible :hover style is now wrapped in @media (hover: hover) so a tap on a phone never latches a hover state until you tap elsewhere. Where hover was fused into a :hover, :focus-visible selector, we split them — keyboard focus stays ungated.
  • Press feedback. :active fires for mouse, pen, and touch, so it’s the one affordance that works everywhere. Buttons, cards, tags, and menu items now give tactile feedback on press — menu items even mirror their highlight so a tap reads instantly.
  • Pointer over mouse. Outside-click dismissal in the color picker and editor moved from mousedown to pointerdown for reliable touch behavior. The deliberate mousedown+preventDefault idiom on remove/clear buttons was left intact — it exists to stop focus theft and already works cross-device.
Press me Secondary Removable

Rather than copy-paste the same rules into 63 files, the reusable pieces live in a single src/styles/interactions.ts module (a pressable fragment and a focusRing), composed into a component’s styles. On mixins: the library already ships the right ones — Focusable, FormAssociatedMixin, NanaEventsMixin — so we invested in wider adoption and shared styles instead of inventing a new class hierarchy on a shipping library.

Everything honors prefers-reduced-motion, and because component styles live in shadow DOM, a page-level motion reset can never leak into them.

The documentation site now holds up from roughly 320px on up:

  • Wide API tables scroll horizontally on narrow screens instead of pushing the whole page sideways.
  • Display type, hero actions, stat strips, and the CTA scale and stack gracefully on small screens.
  • Long URLs and union types wrap instead of overflowing.
  • Native smooth scrolling (scroll-behavior: smooth + scroll-padding-top) eases anchor and table-of-contents jumps — no JavaScript, no dependency — and switches off under prefers-reduced-motion.
  • A centered top-bar search, sized as a real search field, so it’s easy to find at a glance.

A component library earns trust in the small moments: the button that dips when you press it, the menu that doesn’t stick under your thumb, the page that never scrolls sideways on a phone. This release is a down-payment on that trust — and a standard we’ll hold new components to.