55

Is there any way to detect IE browser with React and either redirect to a page or give any helpful message. I found something in JavaScript, but not sure how would I use it with React+TypeScript.

var isEdge = !isIE && !!window.StyleMedia;

Hafiz Temuri
  • 3,882
  • 6
  • 41
  • 66

10 Answers10

89

You are on the right track you can use these to conditionally render jsx or help with routing...

I have used the following with great success.

Originally from - How to detect Safari, Chrome, IE, Firefox and Opera browser?

// Opera 8.0+
const isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;

// Firefox 1.0+
const isFirefox = typeof InstallTrigger !== 'undefined';

// Safari 3.0+ "[object HTMLElementConstructor]" 
const isSafari = /constructor/i.test(window.HTMLElement) || (function (p) { return p.toString() === "[object SafariRemoteNotification]"; })(!window['safari'] || (typeof safari !== 'undefined' && safari.pushNotification));

// Internet Explorer 6-11
const isIE = /*@cc_on!@*/false || !!document.documentMode;

// Edge 20+
const isEdge = !isIE && !!window.StyleMedia;

// Chrome 1 - 71
const isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);

// Blink engine detection
const isBlink = (isChrome || isOpera) && !!window.CSS;

Please be aware they each stand a chance to deprecated due to browser changes.

I use them in React like this:

 content(props){
    if(!isChrome){
     return (
      <Otherjsxelements/>
     )
    }
    else { 
     return (
      <Chromejsxelements/>
     )
    }
  }

Then by calling {this.Content()} in my main component to render the different browser specific elements.

Pseudo code might look something like this... (untested):

import React from 'react';

const isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);

export default class Test extends React.Component {

  content(){
    if(isChrome){
        return (
            <div>Chrome</div>
        )
    } else {
        return (
            <div>Not Chrome</div>
        )
    }
  }

    render() {
        return (
            <div>Content to be seen on all browsers</div>
            {this.content()}
        )
    }
}
BDMayhem
  • 5
  • 2
Shawn Matthews
  • 1,762
  • 1
  • 15
  • 21
  • You could have this change modal content for instance, or even depending on your router have it call a function and redirect you to a help page. Please just let me know if you need an additional breakdown of where these parts each fit inside of the component. – Shawn Matthews Mar 16 '18 at 19:58
  • It might be a good idea to look into a library like the one @Tallboy provided as that stands a better chance of being updated more regularly. Then just use the example I provided for the React integration. – Shawn Matthews Mar 16 '18 at 20:11
  • Maybe try this... let isSafari = navigator.userAgent.indexOf("Safari") > -1; these methods are changed fairly often. – Shawn Matthews Jun 04 '18 at 19:32
  • These are now deprecated – quick007 Apr 29 '21 at 20:43
  • As mentioned, isChrome only works upto version 71. But can't use it for current version 95. This is not a solution for chrome then. – backslashN Nov 17 '21 at 12:01
31

Not sure why but nobody mentioned this package: react-device-detect The package have a lot browsers checks, plus versions and some other info related. It's really small and it's updated.

You can use:

import { isIE } from 'react-device-detect';
isIE // returns true or false

react-device-detect it's also very small bundlephobia link

Lucas Andrade
  • 4,315
  • 5
  • 29
  • 50
  • 3
    Sure, I got it now @HafizTemuri , but maybe you should try to add that info on your next question, we're devs, not clairvoyants. In my personal opinion the package save us a good time in some ways: firstly because you don't have to make any code yourself and secondly you'll not spend time refactoring that code because some browser version doesn't support your code any more. I enforce the info about the package size because, in my personal opinion, in this case a light package is not an overkill, an overkill is spend time with premature optimization. https://wiki.c2.com/?PrematureOptimization – Lucas Andrade Sep 04 '20 at 15:50
  • 16
    I don't think it's useful to put down this post. A package is a perfectly reasonable way to approach the issue, and does have several advantages, namely that the creator/contributors may have thought of edge cases that you haven't, and that what works and doesn't with device/browser detection changes frequently; I personally would rather not have to update my code every time it does. – Andrew Sep 29 '20 at 20:18
  • 1
    Although I'm a bit late to the discussion, @LucasAndrade was only trying to be helpful. No matter how good one may be in programming, there will almost always be edge cases to miss. – subwaymatch Oct 27 '20 at 07:49
  • @LucasAndrade Seems like someone deleted my comment, but it was in my question in case you missed it, `not sure how would I use it with React+TypeScript`. Packages are good until they get bugs and you overturn everything to update a package, only to realize its filled with bugs, then you spend extra time to downgrade. My theory is, write it yourself if you can. And for such a small problem, I don't think anyone should be using a package. And of course there needs to be a balance there, don't go in other direction and try to re-invent the wheel. – Hafiz Temuri Apr 07 '21 at 00:10
  • 2
    I just used this package, accessed on Safari and it doesn't work – guest Nov 14 '21 at 00:19
8

This is the service I always use when doing JS/Browser based browser-detection: http://is.js.org/

if (is.ie() || is.edge()) {
  window.location.href = 'http://example.com';
}
Tallboy
  • 12,847
  • 13
  • 82
  • 173
  • 1
    This could end up in never ending redirect loop. This is not an ideal way of handling it in my opinion. – Hafiz Temuri Mar 16 '18 at 21:53
  • 1
    How would an infinite redirect happen in my case? You simply would ensure that doesn't happen on that page. How else would you redirect to a page based on browser though without creating a situation for a potential redirect loop? – Tallboy Mar 16 '18 at 22:00
  • 1
    You said in your original message, "redirect to a page", so I answered exactly what you asked. – Tallboy Mar 16 '18 at 22:01
  • 1
    Not to mention, the answer you just marked as correct is identical to my answer without the redirect, which was what you originally asked for. – Tallboy Mar 16 '18 at 22:04
  • redirect to a page of the same application. It could end up in the same `if` statement and making it redirect over and over again. – Hafiz Temuri Mar 16 '18 at 22:04
2

I was using Gatsby for our React site and build was giving me trouble with the accepted answer, so I ended up using a useEffect on load to be able to not render for IE at a minimum:

  const [isIE, setIsIE] = React.useState(false);

  React.useEffect(() => {
    console.log(`UA: ${window.navigator.userAgent}`);
    var msie = window.navigator.userAgent.indexOf("MSIE ");
    setIsIE(msie > 0)
  }, []);

  if(isIE) {
    return <></>
  }

// In my component render

if(isIE) { return <></> }

Got the idea originally from:

https://medium.com/react-review/how-to-create-a-custom-usedevicedetect-react-hook-f5a1bfe64599

and

Check if user is using IE

Dfranc3373
  • 2,048
  • 4
  • 30
  • 44
  • What kind of troubles? I personally don't like the use of state and `useEffect` here. You can still implement this approach with a static `const` outside the component. `const isIE = window.navigator.userAgent.indexOf("MSIE ") > 0`. You can still keep the check in your component. `if (isIE)` – Hafiz Temuri Mar 16 '21 at 19:20
  • @HafizTemuri use of `document` or `documentMode` in gatsby build throws a variety of errors and it also has trouble using `window` logic on build as well. By putting inside a hook, it doesn't run on build and allows HTML to be compiled fully, and then on run, actually define the variables. – Dfranc3373 Mar 18 '21 at 15:35
  • and people use a framework like that? That would drive me nuts if I cannot use `window` object. And a lot of time we don't need to put things in `useState`. They should have a `window` available especially when they claim to generate static HTML. – Hafiz Temuri Mar 18 '21 at 16:01
1

Try:

const isEdge = window.navigator.userAgent.indexOf('Edge') != -1
const isIE = window.navigator.userAgent.indexOf('Trident') != -1 && !isEdge

etc.

Each browser has a distinct user agent you can check.

These can be faked by the client of course, but in my opinion, are a more reliable long term solution.

Lev
  • 1,698
  • 3
  • 18
  • 26
1

You can write test for IE like this.

<script>
     // Internet Explorer 6-11
          const isIE = document.documentMode;
          if (isIE){
            window.alert(
              "Your MESSAGE here."
            )
          }
</script>
Qui-Gon Jinn
  • 3,722
  • 3
  • 25
  • 32
1

This almost broke me, but I found something which seems pretty simple and straight forward, use the vendor name. ie. Google, Apple etc. navigator.vendor.includes('Apple') I hope this helps someone out there.

Punter Bad
  • 473
  • 7
  • 14
0

You can try this:

navigator.browserDetection= (function(){
    var ua= navigator.userAgent, tem, 
    M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
    if(/trident/i.test(M[1])){
        tem=  /\brv[ :]+(\d+)/g.exec(ua) || [];
        return 'IE '+(tem[1] || '');
    }
    if(M[1]=== 'Chrome'){
        tem= ua.match(/\b(OPR|Edge)\/(\d+)/);
        if(tem!= null) return tem.slice(1).join(' ').replace('OPR', 'Opera');
    }
    M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
    if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
    return M.join(' ');
})();

console.log(navigator.browserDetection); // outputs: `Chrome 92`
Safaetul Ahasan Piyas
  • 1,285
  • 1
  • 8
  • 10
0

There is a new package that takes care of this for React: https://www.npmjs.com/package/react-browser-navigator

This is how you can use it:

// import the module
import useNavigator from "react-browser-navigator";

function App() {
  // importing the property
  let { userAgent } = useNavigator();

  // you can use it within the useEffect hook OR simply print the 
  // string into the return statement
  useEffect(() => {
    if (!isNull(userAgent)) {
      // printing out the entire object
      console.log("userAgent", userAgent);
    }
  }, [userAgent]);

  return (
    <div>
      <span>userAgent:</span> {userAgent}
    </div>
  );
}

Essentially, the output will be something like this:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36
-1

This is all information you can get from your the browser of you client (using react):

    let latitude
    let longitude
    const location = window.navigator && window.navigator.geolocation

    if (location) {
      location.getCurrentPosition(position => {
        latitude = position.coords.latitude
        longitude = position.coords.longitude
      })
    }

    var info = {
      timeOpened: new Date(),
      timezone: new Date().getTimezoneOffset() / 60,
      pageon: window.location.pathname,
      referrer: document.referrer,
      previousSites: window.history.length,
      browserName: window.navigator.appName,
      browserEngine: window.navigator.product,
      browserVersion1a: window.navigator.appVersion,
      browserVersion1b: navigator.userAgent,
      browserLanguage: navigator.language,
      browserOnline: navigator.onLine,
      browserPlatform: navigator.platform,
      javaEnabled: navigator.javaEnabled(),
      dataCookiesEnabled: navigator.cookieEnabled,
      dataCookies1: document.cookie,
      dataCookies2: decodeURIComponent(document.cookie.split(';')),
      dataStorage: localStorage,
      sizeScreenW: window.screen.width,
      sizeScreenH: window.screen.height,
      sizeDocW: window.document.width,
      sizeDocH: window.document.height,
      sizeInW: window.innerWidth,
      sizeInH: window.innerHeight,
      sizeAvailW: window.screen.availWidth,
      sizeAvailH: window.screen.availHeight,
      scrColorDepth: window.screen.colorDepth,
      scrPixelDepth: window.screen.pixelDepth,
      latitude,
      longitude
    }
    console.log(info)

The browser is browserName

Alan
  • 9,167
  • 4
  • 52
  • 70
  • 1
    Even though I am using `Chrome` but it still says `Netscape` for `window.navigator.appName` – Hafiz Temuri Oct 29 '19 at 22:09
  • Same result for `Firefox`, `Edge` and `IE` – Hafiz Temuri Oct 29 '19 at 22:11
  • right.. I founded chrome in: `"browserVersion1a": "5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"` and `"browserVersion1b": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"` – Alan Oct 29 '19 at 23:34
  • Thanks, I know that is informative, but I dont think this will be helpful. Since you will have to do a lot of parsing to get the name out. Plus if they decided to change the format it will stop working. I am going to stick with @Shawn Matthews's answer for now. – Hafiz Temuri Oct 30 '19 at 13:14