How to detect if JavaScript is disabled?

Viewed 493120

There was a post this morning asking about how many people disable JavaScript. Then I began to wonder what techniques might be used to determine if the user has it disabled.

Does anyone know of some short/simple ways to detect if JavaScript is disabled? My intention is to give a warning that the site is not able to function properly without the browser having JS enabled.

Eventually I would want to redirect them to content that is able to work in the absence of JS, but I need this detection as a placeholder to start.

39 Answers

I assume you're trying to decide whether or not to deliver JavaScript-enhanced content. The best implementations degrade cleanly, so that the site will still operate without JavaScript. I also assume that you mean server-side detection, rather than using the <noscript> element for an unexplained reason.

There is no good way to perform server-side JavaScript detection. As an alternative it is possible to set a cookie using JavaScript, and then test for that cookie using server-side scripting upon subsequent page views. However this would be unsuitable for deciding what content to deliver, as it would not distinguish visitors without the cookie from new visitors or from visitors who did not accept the JavaScript set cookie.

noscript blocks are executed when JavaScript is disabled, and are typically used to display alternative content to that you've generated in JavaScript, e.g.

<script type="javascript">
    ... construction of ajaxy-link,  setting of "js-enabled" cookie flag, etc..
</script>
<noscript>
    <a href="next_page.php?nojs=1">Next Page</a>
</noscript>

Users without js will get the next_page link - you can add parameters here so that you know on the next page whether they've come via a JS/non-JS link, or attempt to set a cookie via JS, the absence of which implies JS is disabled. Both of these examples are fairly trivial and open to manipulation, but you get the idea.

If you want a purely statistical idea of how many of your users have javascript disabled, you could do something like:

<noscript>
    <img src="no_js.gif" alt="Javascript not enabled" />
</noscript>

then check your access logs to see how many times this image has been hit. A slightly crude solution, but it'll give you a good idea percentage-wise for your user base.

The above approach (image tracking) won't work well for text-only browsers or those that don't support js at all, so if your userbase swings primarily towards that area, this mightn't be the best approach.

This is what worked for me: it redirects a visitor if javascript is disabled

<noscript><meta http-equiv="refresh" content="0; url=whatyouwant.html" /></noscript>

I'd suggest you go the other way around by writing unobtrusive JavaScript.

Make the features of your project work for users with JavaScript disabled, and when you're done, implement your JavaScript UI-enhancements.

https://en.wikipedia.org/wiki/Unobtrusive_JavaScript

If your use case is that you have a form (e.g., a login form) and your server-side script needs to know if the user has JavaScript enabled, you can do something like this:

<form onsubmit="this.js_enabled.value=1;return true;">
    <input type="hidden" name="js_enabled" value="0">
    <input type="submit" value="go">
</form>

This will change the value of js_enabled to 1 before submitting the form. If your server-side script gets a 0, no JS. If it gets a 1, JS!

You can use a simple JS snippet to set the value of a hidden field. When posted back you know if JS was enabled or not.

Or you can try to open a popup window that you close rapidly (but that might be visible).

Also you have the NOSCRIPT tag that you can use to show text for browsers with JS disabled.

You'll want to take a look at the noscript tag.

<script type="text/javascript">
...some javascript script to insert data...
</script>
<noscript>
   <p>Access the <a href="http://someplace.com/data">data.</a></p>
</noscript>

The noscript tag works well, but will require each additional page request to continue serving useless JS files, since essentially noscript is a client side check.

You could set a cookie with JS, but as someone else pointed out, this could fail. Ideally, you'd like to be able to detect JS client side, and without using cookies, set a session server side for that user that indicates is JS is enabled.

A possibility is to dynamically add a 1x1 image using JavaScript where the src attribute is actually a server side script. All this script does is saves to the current user session that JS is enabled ($_SESSION['js_enabled']). You can then output a 1x1 blank image back to the browser. The script won't run for users who have JS disabled, and hence the $_SESSION['js_enabled'] won't be set. Then for further pages served to this user, you can decide whether to include all of your external JS files, but you'll always want to include the check, since some of your users might be using the NoScript Firefox add-on or have JS disabled temporarily for some other reason.

You'll probably want to include this check somewhere close to the end of your page so that the additional HTTP request doesn't slow down the rendering of your page.

If javascript is disabled your client-side code won't run anyway, so I assume you mean you want that info available server-side. In that case, noscript is less helpful. Instead, I'd have a hidden input and use javascript to fill in a value. After your next request or postback, if the value is there you know javascript is turned on.

Be careful of things like noscript, where the first request may show javascript disabled, but future requests turn it on.

You might, for instance, use something like document.location = 'java_page.html' to redirect the browser to a new, script-laden page. Failure to redirect implies that JavaScript is unavailable, in which case you can either resort to CGI ro utines or insert appropriate code between the tags. (NOTE: NOSCRIPT is only available in Netscape Navigator 3.0 and up.)

credit http://www.intranetjournal.com/faqs/jsfaq/how12.html

A technique I've used in the past is to use JavaScript to write a session cookie that simply acts as a flag to say that JavaScript is enabled. Then the server-side code looks for this cookie and if it's not found takes action as appropriate. Of course this technique does rely on cookies being enabled!

I think you could insert an image tag into a noscript tag and look at the stats how many times your site and how often this image has been loaded.

People have already posted examples that are good options for detection, but based on your requirement of "give warning that the site is not able to function properly without the browser having JS enabled". You basically add an element that appears somehow on the page, for example the 'pop-ups' on Stack Overflow when you earn a badge, with an appropriate message, then remove this with some Javascript that runs as soon as the page is loaded (and I mean the DOM, not the whole page).

code inside <noscript> tags will be executed when there is no js enabled in browser. we can use noscript tags to display msg to turn on JS as below.<noscript> <h1 style="text-align: center;">enable java script and reload the page</h1> </noscript> while keeping our website content inside body as hidden. as below

<body>
<div id="main_body" style="display: none;">
website content.
</div>
</body>

now if JS is turned on you can just make the content inside your main_body visible as below

<script type="text/javascript">
document.getElementById("main_body").style.display="block";
</script>

Detect it in what? JavaScript? That would be impossible. If you just want it for logging purposes, you could use some sort of tracking scheme, where each page has JavaScript that will make a request for a special resource (probably a very small gif or similar). That way you can just take the difference between unique page requests and requests for your tracking file.

Adding a refresh in meta inside noscript is not a good idea.

  1. Because noscript tag is not XHTML compliant

  2. The attribute value "Refresh" is nonstandard, and should not be used. "Refresh" takes the control of a page away from the user. Using "Refresh" will cause a failure in W3C's Web Content Accessibility Guidelines --- Reference http://www.w3schools.com/TAGS/att_meta_http_equiv.asp.

Of course, Cookies and HTTP headers are great solutions, but both would require explicit server side involvement.

For simple sites, or where I don't have backend access, I prefer client side solutions.

--

I use the following to set a class attribute to the HTML element itself, so my CSS can handle pretty much all other display type logic.

METHODS:

1) place <script>document.getElementsByTagName('html')[0].classList.add('js-enabled');</script> above the <html> element.

WARNING!!!! This method, will override all <html> class attributes, not to mention may not be "valid" HTML, but works in all browsers, I've tested it in.

*NOTES: Due to the timing of when the script is run, before the <html> tag is processed, it ends up getting an empty classList collection with no nodes, so by the time the script completes, the <html> element will be given only the classes you added.

2) Preserves all other <html> class attributes, simply place the script <script>document.getElementsByTagName('html')[0].classList.add('js-enabled');</script> right after the opening <html> tag.

In both cases, If JS was disabled, then no changes to the <html> class attributes will be made.

ALTERNATIVES

Over the years I've used a few other methods:

    <script type="text/javascript">
    <!-- 
        (function(d, a, b){ 
            let x = function(){
                // Select and swap
                let hits = d.getElementsByClassName(a);
                for( let i = hits.length - 1; i >= 0; i-- ){
                    hits[i].classList.add(b);
                    hits[i].classList.remove(a);
                }
            };
            // Initialize Second Pass...
            setTimeout(function(){ x(); },0);
            x();
        })(document, 'no-js', 'js-enabled' );
    -->
</script>

// Minified as:

<script type="text/javascript">
    <!-- 
        (function(d, a, b, x, hits, i){x=function(){hits=d.getElementsByClassName(a);for(i=hits.length-1;i>=0;i--){hits[i].classList.add(b);hits[i].classList.remove(a);}};setTimeout(function(){ x(); },0);x();})(document, 'no-js', 'js-enabled' );
    -->
</script>
  • This will cycle through the page twice, once at the point where it is in the page, generally right after the <html> and once again after page load. Two times was required, as I injected into a header.tpl file of a CMS which I did not have backend access to, but wanted to present styling options for no-js snippets.

The first pass, would set set the .js-enabled class permitting any global styles to kick in, and prevented most further reflows. the second pass, was a catchall for any later included content.

REASONINGS:

The main reasons, I've cared if JS was enabled or not was for "Styling" purposes, hide/show a form, enable/disable buttons or restyle presentation and layouts of sliders, tables, and other presentations which required JS to function "correctly" and would be useless or unusable without JS to animate or handle the interactions.

Also, you can't directly detect with javascript, if javascript is "disabled"... only if it is "enabled", by executing some javascript, so you either rely on <meta http-equiv="refresh" content="2;url=/url/to/no-js/content.html" /> or you can rely on css to switch styles and if javascript executes, to switch to a "js-enabled" mode.

Why do you need to know server-side if JavaScript is enabled? Does it matter which variant the browser supports? Does it e.g. need to understand keyword let or is just var okay?

I'd recommend sending readable content that doesn't require any JavaScript to be accessible and then just try to load JS file to add all the JS behaviors you want in addition.

For example, the UI might end up missing Login or Modify button if JS is not enabled and it might include a small text at the bottom (using <noscript> or some element with CSS animation that shows the text after a small delay if JS code doesn't remove the whole element soon enough) saying "To login/modify this content, you must enable JavaScript support in your browser." If you do this well, the reader may not even notice that anything is missing unless he or she is trying to login or modify the content.

As an optimization you could then set cookie with JavaScript and the server could avoid sending the non-JavaScript readable content if you wish to acquire it asyncronously for some reason. Just make sure to only set this cookie after the JS code has run into completion at least once, instead of setting it immediately the JS code starts to run, to make sure that the end user doesn't end up with a blank screen when (not if!) the JS code fails for any reason.

(Note that loading the initial page state asyncronous will not get that content to end user any faster. However, you could only send part of the total content without JavaScript. That could allow rendering "above the fold" faster and then asyncronously load rest of the page using JS code.)

As an added bonus, search engines can still index your site without any JavaScript enabled.

Update 2022

This question has already over 30 answers, but none of them seem to be clear or precise on what had to be done.

  • Server Side Framework Used - ASP.NET Core
  • Client side - vanilla js

On BaseController where the first entry point on the app which is OnActionExecutionAsync I have this piece of logic.

  • Basically by default I assume client does not have javascript enabled and set this flag.
Response.Cookies.Append("jsEnabled", "false");
  • Now after initial load on client I have a javascript function that updates this flag to true.
  • This function will only have run when the environment has javascript

So the full solution is here.

Client

On Initial load add this function

function detectIfJavascriptIsEnabled() {
    // if this function run's which means js is enabled
    var jsEnabled = getCookie('jsEnabled');
    if (jsEnabled === 'false') {
        setCookie('jsEnabled', 'true');
        location.reload();
    }
}

Server

private bool ValidateIfEnvironmentHasJavascript() {
  if (HttpContext.Request.Cookies != null && HttpContext.Request.Cookies.Count > 0) {
    Boolean.TryParse(HttpContext.Request.Cookies["jsEnabled"], out
      var hasJavascriptEnabled);
    return hasJavascriptEnabled;
  } else {
    Response.Cookies.Append("jsEnabled", "false",
      new CookieOptions() {
        IsEssential = true, Expires = DateTime.UtcNow.AddHours(24)
      });
  }

  return false;
}

This is how you get the result

var environmentHasJavascript = ValidateIfEnvironmentHasJavascript();
Related