bug: isMobile returns true for touch screen laptops
Prerequisites
- [X] I have read the Contributing Guidelines.
- [X] I agree to follow the Code of Conduct.
- [X] I have searched for existing issues that already report this problem, without success.
Ionic Framework Version
- [ ] v4.x
- [X] v5.x
- [X] v6.x
Current Behavior
Platform#isMobile function is querying for (any-pointer: coarse), which means it will return true when at least one input device uses a touch mechanism. An app running on my laptop Platform#isMobile is returning true because it has an input device that uses a touch mechanism.
Expected Behavior
Platform#isMobile function should be querying for (pointer: coarse), which means it will return true only when the primary input device uses a touch mechanism. An app running on my laptop Platform#isMobile is returning false because it has not an input device that uses a touch mechanism as its primary input device.
Steps to Reproduce
- Get a laptop that has a touch screen.
- Start a new ionic app with a blank template
- use the platform service and note that platform#platforms return
["mobile", "mobileweb"]
Code Reproduction URL
https://github.com/NormanV41/ionic-issues-demo
Ionic Info
[WARN] Error loading @capacitor/ios package.json: Error: Cannot find module '@capacitor/ios/package'
Require stack:
- /usr/lib/node_modules/@ionic/cli/lib/project/index.js
- /usr/lib/node_modules/@ionic/cli/lib/index.js
- /usr/lib/node_modules/@ionic/cli/index.js
- /usr/lib/node_modules/@ionic/cli/bin/ionic
[WARN] Error loading @capacitor/android package.json: Error: Cannot find module '@capacitor/android/package'
Require stack:
- /usr/lib/node_modules/@ionic/cli/lib/project/index.js
- /usr/lib/node_modules/@ionic/cli/lib/index.js
- /usr/lib/node_modules/@ionic/cli/index.js
- /usr/lib/node_modules/@ionic/cli/bin/ionic
Ionic:
Ionic CLI : 6.18.0 (/usr/lib/node_modules/@ionic/cli) Ionic Framework : @ionic/angular 6.0.0-rc.2 @angular-devkit/build-angular : 12.1.4 @angular-devkit/schematics : 12.1.4 @angular/cli : 12.1.4 @ionic/angular-toolkit : 4.0.0
Capacitor:
Capacitor CLI : 3.2.5 @capacitor/android : not installed @capacitor/core : 3.2.5 @capacitor/ios : not installed
Utility:
cordova-res : 0.15.3 native-run : 1.5.0
System:
NodeJS : v14.16.1 (/usr/bin/node) npm : 6.14.12 OS : Linux 5.14
Additional Information
No response
I corroborate this. On a Surface Laptop Studio device, which has a touch screen but is really a laptop, getPlatforms returns mobile and mobileweb:

@liamdebeasi I read the discussion on Pixel 7 devices. While for that one the issue seems to lie inside Chromium, I don't know what can be done here.
EDIT: I ran the following snippet
["none", "coarse", "fine"].forEach(precision => {
console.log(`matchMedia("(any-pointer:${precision})"): ${matchMedia(`(any-pointer:${precision})`).matches}`);
console.log(`matchMedia("(pointer:${precision})"): ${matchMedia(`(pointer:${precision})`).matches}`);
});
in the console for both Chrome and Edge and both any-pointer:coarse and pointer:coarse return true on the Surface.
Thanks for checking! Are you able to provide the raw results for all the precision types?
@liamdebeasi I was making a mistake in the media query (forgot the parenthesis), I get true for both any-pointer:coarse and pointer:coarse on both Chrome and Edge. To recap:
["none", "coarse", "fine"].forEach(precision => {
console.log(`matchMedia("(any-pointer:${precision})"): ${matchMedia(`(any-pointer:${precision})`).matches}`);
console.log(`matchMedia("(pointer:${precision})"): ${matchMedia(`(pointer:${precision}`).matches})`);
});
Chrome:

Edge:

even when I only use an external monitor and disable the Surface's monitor!
Not sure what to do 🤔
Thanks! It sounds like this may be an issue with browsers instead of Ionic:
Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1638556 Chrome: https://bugs.chromium.org/p/chromium/issues/detail?id=1088262&q=windows%20surface%20pointer&can=2
It sounds like pointer:fine should be returning true when a mouse is attached/tablet mode is disabled, but browsers do not report this currently. I am going to update this thread to mark the issue as an external bug. If this is a browser bug you need fixed, I recommend commenting on the bug threads above.
This issue is not specific for surface devices. It probably happens on any device with a touchscreen. For example I have a Dell Laptop with a touchscreen and isMobile returns true.
Maybe there is a bug in the browsers, I don't know. But I still think there is also a bug in Ionic. For me the media queries seem to return valid results. Same result in three browsers (Chrome / Edge / Firefox): window.matchMedia("(any-pointer:none)"): false window.matchMedia("(pointer:none)"): false) window.matchMedia("(any-pointer:coarse)"): true window.matchMedia("(pointer:coarse)"): false) window.matchMedia("(any-pointer:fine)"): true window.matchMedia("(pointer:fine)"): true)
So the initial question remains.
Why does isMobile check for (any-pointer: coarse). Shouldn't it be (pointer: coarse) to check the primary input device, or (any-pointer:fine)?
There have also been other issues to report that problem, like #18388 and #17833. They were closed refering to #17631. But the latter is closed now and the issue still exists. Is there any plan on how to proceed with this issue?
Even if this is not an ionic bug we should find a solution for it as a framework we should abstract this bug from the consumers.
What if we add a check for || !!window.cordova || !!window.Capacitor
Since it's my understanding those only get injected into the native builds. This might be a breaking change for anyone accidentally loading cordova or capacitor on web but I think it's an acceptable.
When (if) the browsers fix the issue we can remove