Detect input capabilities
A coarse pointer does not mean “mobile”, and a fine pointer does not guarantee “desktop”. Ask the browser about input capabilities instead of guessing the device from its user agent.
const input = {
finePointer: matchMedia('(any-pointer: fine)').matches,
coarsePointer: matchMedia('(any-pointer: coarse)').matches,
canHover: matchMedia('(any-hover: hover)').matches,
};
Hybrid laptops can report both fine and coarse pointers. Adapt the interaction to capabilities, and keep the same task possible with keyboard and touch.