/** * Detects if the primary pointing device or environment is a touch device * (e.g. tablet, phone, POS touchscreen terminal). * Returns false on desktop devices with mice/trackpads even if they have touchscreens. */ export function isTouchDevice() { if (typeof window === 'undefined') return false; if (window.matchMedia) { if (window.matchMedia('(pointer: coarse)').matches) { return true; } if (window.matchMedia('(pointer: fine)').matches) { return false; } } return 'ontouchstart' in window || (navigator.maxTouchPoints > 0); } /** * Globally disables autofocus on touch devices to prevent virtual keyboard popups. * Physical taps on inputs still focus and open the keyboard normally. */ export function disableTouchAutofocus() { if (!isTouchDevice()) return; // 1. Intercept programmatic focus called during mount/render on autofocus elements const originalFocus = HTMLElement.prototype.focus; HTMLElement.prototype.focus = function (options) { if (this.hasAttribute?.('autofocus') || this.autofocus) { this.removeAttribute?.('autofocus'); try { this.autofocus = false; } catch { // ignore } return; } const stack = new Error().stack || ''; if (stack.includes('commitMount') || stack.includes('commitHostUpdate')) { return; } return originalFocus.call(this, options); }; // 2. Prevent browser from honoring native autofocus attribute on dynamically inserted elements const originalSetAttribute = Element.prototype.setAttribute; Element.prototype.setAttribute = function (name, value) { if (typeof name === 'string' && name.toLowerCase() === 'autofocus') { return; } return originalSetAttribute.call(this, name, value); }; }