I know jQuery. Now what?

I gave this talk: I know jQuery. What now? at jQuery UK 2013 (video of the talk), but instead of my usual approach of post-it explosion on my desk, I wrote a post first, and created the slides from the post. So here is my (fairly unedited) quasi-ramble on how I used jQuery, and how I’m looking at where I’m using native browser technology.

Addition resources

As this post was also the content for a talk I’ve given, I’ve added addition resources as they’ve been published below:

7 years ago…

17-Jun 2006, I publish my first (ever) real blog post: taking regular JavaScript and simplifying to jQuery syntax. It turned 14 lines of JavaScript in to 3 lines of jQuery (pre jQuery 1.0).

Most importantly, it went from some fiddly DOM navigation to a simple CSS expression, and added a class once done. The original JavaScript was also quite brittle, so it meant you either had the same markup.

I introduced jQuery to the team of developers I worked with back in mid-2000s and even the designers could see the appeal (since they generally understood CSS selectors (and hence how jQuery for Designers was born)).

DOM navigating was suddenly easy

Back then the DOM was hard to navigate. You could be sure that if it worked in Firefox 1.5, it wouldn’t work in IE6.

The ease in which jQuery could be learnt was the appeal to me. All the DOM navigation was done using CSS expression using some insane black box magic that John Resig had come up – saving my limited brain power, and once I had those DOM nodes, I could do what I wanted to them (usually some combinations of showing, hiding, fading and so on).

Groking ajax

jQuery also abstracted ajax for me. The term had only just been coined earlier in 2005, but documentation was not wide, nor trivial to understand (remember the lower power computing power of my brain).

It was the first time I really had to deal with the XMLHttpRequest object, and when seeing it for the first time, understanding the onreadystatechange event and the combination of this.status and this.readyState wasn’t overtly clear! jQuery (and other libraries) also tucked away the mess that was XHR in IE via ActiveX…

function getXmlHttpRequest() {
  var xhr;
  if (window.XMLHttpRequest) {
    xhr = new XMLHttpRequest();
  } else {
    try {
      xhr = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (e) {
        xhr = false;
  return xhr;

// disclaimer: John's jQuery version is a lot more elegant!

Once I could see that using the ajax utility inside of jQuery to suck in a URL’s HTML (which was typically the way we wanted to do ajax), then ajax suddenly clicked.

jQuery quickly became my standard utility for many years. It was my Swiss Army Knife, as it were, to steal Adam’s talk title!

Back to the future: today

Let’s fast forward back to today. What’s happened over those years?

For starters, my default starting position is no longer “include jQuery by default”. I understand more JavaScript and how things work.

I have my own criteria for when to include jQuery, and when not to include jQuery. But if I don’t include jQuery, then what?

In those 7 years, quite a bit has happened. Probably one of the most important steps forward was the introduction of querySelectorAll.

Being able to give a native function of a browser a CSS expression, and it doing the work to navigate the DOM is a huge (literally) part of jQuery. Basic support was in Chrome from the outset, and in IE8 and Firefox 3.5 around mid-2009.

Andrew Lunny (of PhoneGap & Adobe) has the brilliant simplicity on the bling function:

var $ = document.querySelectorAll.bind(document);
Element.prototype.on = Element.prototype.addEventListener;

$('#somelink')[0].on('touchstart', handleTouch);

Beautifully simple.

I’ve taken this idea a little further and used it on a few specific projects, adding support for chaining, looping and simplifying the syntax. Comes in at <200 bytes gzipped. But the point is that today we have features natively available, and I’m trying to consider my audience before dropping in jQuery by default.

When I always use jQuery

Before I look at how I can go without jQuery, naked, let me just share when I drop jQuery in to a project. There’s usually a few of very specific criteria that either has me start with jQuery or switch from a bespoke solution in favour of jQuery.

Before I do, I should point out when I absolutely don’t use jQuery: If I’m trying to replicate a browser bug, I never use a library. If you’re trying to corner a bug, so that you can file an issue, you want your case as minimal as possible (unless of course you’re filing a bug on jQuery!).

1. When the project has to work in non-cutting-mustard browsers

The BBC have been quite vocal in what they define as “cutting the mustard“, and now I think about it, that’s my benchmark for when to include jQuery by default.

If I know I have to work with browsers that don’t cut the mustard, and they’re part of the core audience, then I’ll start with jQuery in my initial code.

What is cutting the mustard?

It’s almost as simple as: does this browser have querySelectorAll?

The BBC use the following test for cutting the mustard:

if ('querySelector' in document && 
    'localStorage' in window && 
    'addEventListener' in window) {
    // bootstrap the JavaScript application

I know off the top of my head IE8 doesn’t support addEventListener (but there is a polyfill), so if that’s an important browser to the project, then I know that I don’t want to start the project hoop jumping for IE8.

This isn’t to say those projects that I start without jQuery won’t support IE8, it’s more that you want to start simple, and keep development simple from the outset. If I start a project with a bag of hacks – I know it’s going to be a hassle.

I also class this as “when complexity outweighs ease”.

2. When it’s quick and dirty

If I’m creating a proof of concept, testing an idea out, and generally hacking and creating a JS Bin, I’m usually adding jQuery by default. It saves me thinking.


You might be thinking “so, does Remy use jQuery, and if he doesn’t then does he just re-implement it all?”.

I certainly don’t want to re-invent the wheel. If I find that developing without jQuery only leads me to re-creating a lot of jQuery’s functionality from scratch, then I’m clearly wasting my own time.

No, there’s a lot of patterns where I will build my application code without a library and rely on native browser technology to do the job. And if there’s a small part of that functionality missing, I might turn to polyfills – but only after careful review that it makes sense.

So how do I live without jQuery, and how good is the support?


Even when I use jQuery, if I (or my company) have control of the project, I very, very rarely use document.ready (or the shortened version $(function)).

This is because I put all my JavaScript below my DOM, before the </body> tag. This way I always know the DOM is going to be compiled by this point.

Hopefully it’s common knowledge by now, but JavaScript blocks rendering. Put your JavaScript above the content, and your server stalls, and you get a blank page. I’ve used this example many times before, but twitter’s “badge” (a long time ago) used to be put inline to your HTML. Their site would often go down, and as my blog (also carrying the twitter badge) would hang with a blank page – giving the appearance that my site was down.

.attr(‘value’) and .attr(‘href’)

It makes me sad when I see jQuery to retrieve a value from an input element:

$('input').on('change', function () {
  var value = $(this).attr('value');

  alert('The new value is' + value);

Why? Because you can get to the value using this.value. More importantly – you should think about how you’re using a JavaScript library. Don’t unnecessarily invoke jQuery if you don’t need to.

In fact, this isn’t a jQuery thing – it’s a best practise thing. The code should simply read:

$('input').on('change', function () {

  alert('The new value is' + this.value);

It’s also common to use jQuery to get the href of an anchor: $(this).attr('href'), but you can also easily get this from knowing the DOM: this.href. However, note that this.href is different, it’s the absolute url, as we’re talking about the DOM API, and not the element. If you want the attribute value (as it’s suggested in the jQuery version), you want this.getAttribute('href').

Then there’s setting the class on an element, you don’t need jQuery for that either if you’re just adding a class.

I’ve seen this before:

  <script src="http://code.jquery.com/jquery.min.js"></script>

But why not:

    document.body.className = 'hasJS';

Probably the most important change in the version below, is there’s no jQuery being included first just to set a class name on the body to determine whether JavaScript is available.

If the body might have a class already, just append (jQuery has to read the className property too): document.body.className += ' hasJS'.

And this is where we start to run in to issues with class names and tracking what classes they have and don’t have. But browsers have this functionality natively too.

classList for add, remove & toggle

HTML5′s classList support is in all the latest production browsers (note not in IE9 – but this is a case where I might choose to polyfill).

Instead of:


// or

document.body.className += ' hasJS';

We can do:


Isn’t that pretty?

What about removing:


// or some crazy ass regular express

Or we can do:


But more impressive is the native toggle support:


// and


To set multiple classes, you add more arguments:

document.body.classList.add('hasJS', 'ready');

What does suck though, is the weird issues – like don’t use a empty string:

// SyntaxError: DOM Exception 12

That’s pretty rubbish. But! On the upside, I know the problem areas and I avoid them. Pretty much what we’ve grown up on working with browsers anyway.

Storing data

jQuery implemented arbitrary data storage against elements in 1.2.3 and then object storing in 1.4 – so a little while ago.

HTML5 has native data storage against elements, but there’s a fundamental difference between jQuery and native support: object storage won’t work in HTML5 dataset.

But if you’re storing strings or JSON, then native support is perfect:

element.dataset.user = JSON.stringify(user);
element.dataset.score = score;

Support is good, but sadly no native support in IE10 (though you can add a polyfill and it’ll work perfectly again – but that’s a consideration when using dataset).


Like I said before, jQuery helped me grok ajax fully. But now ajax is pretty easy. Sure, I don’t have all the extra options, but more often than not, I’m doing an XHR GET or POST using JSON.

function request(type, url, opts, callback) {
  var xhr = new XMLHttpRequest(),

  if (typeof opts === 'function') {
    callback = opts;
    opts = null;

  xhr.open(type, url);

  if (type === 'POST' && opts) {
    fd = new FormData();

    for (var key in opts) {
      fd.append(key, JSON.stringify(opts[key]));

  xhr.onload = function () {

  xhr.send(opts ? fd : null);

var get = request.bind(this, 'GET');
var post = request.bind(this, 'POST');

It’s short and simple. XHR is not hard and it’s well documented nowadays. But more importantly, having an understanding of how it really works and what XHR can do, gives us more.

What about progress events? What about upload progress events? What about posting upstream as an ArrayBuffer? What about CORS and the xml-requested-with header?

You’ll need direct access to the XHR object for this (I know you can get this from jQuery), but you should get familiar with the XHR object and it’s capabilities, because things like file uploads via drag and drop is insanely easy with native functionality today.

Finally forms!

The jQuery form validation plugin was a stable plugin from the early days of jQuery, and frankly made working with forms so much easier.

But regardless of your client side validation – you must always run server side validation – this remains true regardless of how you validate.

But what if you could throw away lines and lines of JavaScript and plugins to validate an email address like this:

<input type="email">

Want to make it a required field?

<input type="email" required>

Want to allow only specific characters for a user?

<input pattern="[a-z0-9]">

Bosh. It even comes with assistive technology support – i.e. the keyboard will adapt to suit email address characters.

Since these types fall back to text, and you have to have server side validation, I highly encourage you to rip out all your JavaScript validation and swap in native HTML5 form validation.

jQuery animations VS. CSS animations VS. JavaScript animations

It’s not really a contest. CSS wins. Animating using CSS is being processed on the GPU. Animating in JavaScript has the additional layer of computation in the simple fact there’s JavaScript.

Even then, if I’m writing the code myself, I’m going to choose to use requestAnimationFrame over setInterval based animations.

Jake Archibald has some excellent slides showing the issue here, whereby setInterval won’t be smooth and will quickly start to drop frames:



What’s more, CSS animations go through the same scheduler as requestAnimationFrame, which is what we want to use.

So if your browser support allows for it, use CSS animations. Sure, it’s not as easy as $foo.animate('slow', { x: '+=10px' }) but it’s going to be cleaner and smoother. It should be a well known fact that touching the DOM is expensive. So if you’re animating the x position of an element by updating the el.style.left attribute, you’re going back and forth for the animation.

However, if you can simply do foo.classList.add('animate'), the CSS class animate will transition the left position of the element. And you have control if that’s just the left property, or if you take advantage of hardware acceleration by using translateX with translateZ(0).

But what about my animation end callback I hear you all cry?! That’s available too. Though it’s a little icky:

el.addEventListener("webkitTransitionEnd", transitionEnded);
el.addEventListener("transitionend", transitionEnded);
  • Note the the lowercase ‘e’ on ‘end’…

A few kind people on twitter did also point me to a sort-of-polyfill for jQuery, that enhances the .animate function if CSS animations are available.

There’s also a separate plugin called Transit which gives you JavaScript based control over creating CSS animations. A really nice aspect (for me) is the chaining support. Since it relies exclusively on CSS animations, it requires IE10 and above.

Which begs me to ask: why does this plugin require jQuery specifically?

Aside: jQuery plugins – just because.


I don’t know why, but I really want to hurt the people who write jQuery plugins that don’t really need jQuery. /seeks-anger-management


@rem Me too, I suspect there’s a support group for that. Probably rather large.

I was working on a project recently, and knew of the fitText.js project. I went to drop it in, but then spotted that it needed jQuery.

Hmm. Why?

It uses the following jQuery methods:

  1. .extend
  2. .each
  3. .width
  4. .css
  5. .on (and not with much thought to performance)

The plugin is this:

  $.fn.fitText = function( kompressor, options ) {

    // Setup options
    var compressor = kompressor || 1,
        settings = $.extend({
          'minFontSize' : Number.NEGATIVE_INFINITY,
          'maxFontSize' : Number.POSITIVE_INFINITY
        }, options);

    return this.each(function(){

      // Store the object
      var $this = $(this);

      // Resizer() resizes items based on the object width divided by the compressor * 10
      var resizer = function () {
        $this.css('font-size', Math.max(Math.min($this.width() / (compressor*10), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)));

      // Call once to set.

      // Call on resize. Opera debounces their resize by default.
      $(window).on('resize orientationchange', resizer);



.extend is being used against an object that only has two options, so I would rewrite to read:

  if (options === undefined) options = {}; 
  if (options.minFontSize === undefined) options.minFontSize = Number.NEGATIVE_INFINITY;
  if (options.maxFontSize === undefined) options.maxFontSize = Number.POSITIVE_INFINITY;

return this.each used to loop over the nodes. Let’s assume we want this code to work stand alone, then our fitText function would receive the list of nodes (since we wouldn’t be chaining):

  var length = nodes.length,
      i = 0;

  // would like to use [].forEach.call, but no IE8 support
  for (; i < length; i++) {
    (function (node) {
      // where we used `this`, we now use `node`
      // ...

$this.width() gets the width of the container for the resizing of the text. So we need to get the computed styles and grab the width:

  // Resizer() resizes items based on the object width divided by the compressor * 10
  var resizer = function () {
    var width = node.clientWidth;

    // ...

It’s really important to note that swapping .width() for .clientWidth will not work in all plugins. It just happen to be the right swap for this particular problem that I was solving (which repeats my point: use the right tool for the job).

$this.css is used as a setter, so that’s just a case of setting the style:

  node.style.fontSize = Math.max(...);

$(window).on('resize', resizer) is a case of attaching the event handler (note that you’d want addEvent too for IE8 support):

  window.addEventListener('resize', resizer, false);

In fact, I’d go further and store the resizers in an array, and on resize, loop through the array executing the resizer functions.

Sure, it’s a little more work, but it would also easy to upgrade this change to patch in jQuery plugin support as an upgrade, rather than making it a prerequisite.

Rant will be soon over: it also irks me when I see a polyfill requires jQuery – but I know the counter argument to that is that jQuery has extremely high penetration so it’s possibly able to justify the dependency.


My aim was to show you that whilst jQuery has giving me such as huge helping hand over the years (particularly those years of poor interoperability), that native browser support is a long way to doing a lot of the common workflows I have when writing JavaScript to “do stuff” to the DOM.

Forget about X feature doesn’t work in Y browser – approach it from the point of view of: what am I trying to solve? What’s the best tool for the job? What’s my audience?

I still believe in progressive enhancement, but I don’t believe in bending over backwards to support an imaginary user base (because we don’t have data to say what browsers our users are using).

Google (last I read) support latest minus 1. I try to start from the same baseline support too.

I’ll continue to use jQuery the way that suits me, and I’ll continue to evangelise that front end devs learn what the browsers they work with are capable of.

With that then, I close, and I hope this has been helpful to you.

Maybe some of you knew all this already (though I would question why you’re attending/reading this!), hopefully I’ve shown some of you that there’s a world beyond jQuery and that you can start using it today in some of your projects.

Maybe some of you are new to jQuery – I hope that you go on to look further in to what JavaScript and the DOM are capable of.

But for the majority of you: I’m singing to the choir. You’re already invested. You already believe in standards, doing it right, learning and bettering yourself. It’s those people who aren’t getting this information that you need to help.

You need to share your experiences with the others around you. You’re the expert now, and it’s up to you to help those around you, to help them come up to your standards and beyond.

Conferences will be looking for new speakers, new experts: you are that person.

28 Responses to “I know jQuery. Now what?”

  1. This is a brilliant resource, some excellent tips. I have been using some and didn’t know about others (such as toggle in classList).

    I tweeted you but thought I best comment so others can see, to add multiple classes just do this:

  2. Interesting and particularly pertinent points given the huge increase in mobile browser usage over the last few years.

  3. Note that this.value and this.getAttribute('value') aren’t necessarily the same. http://jsbin.com/ozifiv/1

  4. Absolutely – and it’s rare that you want anything other than this.value.

  5. Thanks Remy. Great post with loads of useful information.

  6. I haven’t read the article yet, but I just wanted to say the Neo image at the top made me laugh for a good 2 minutes. Thanks.

  7. Brilliant post Remy. Some really useful snippets and points to think about. Thanks.

  8. Great post :)

    I like when third-party libraries use the adapter pattern so they can work with any framework. Look at History.js for example – It supports jQuery, MooTools and Zepto, and “native” (pure JS) support was added later in the project. The key is to have a wrapper around jQuery, which can be easily swapped out. This is good practice anyways – Your library should not be tightly coupled to a mostly unrelated one.

    History.js doesn’t really need it (I’m sure it’d be fine with just the ‘native’ library), but this is a great idea for any libraries that do extensive DOM manipulation. Get the full power of jQuery or MooTools if they’re available, and otherwise fall back to native browser support. I hate having to load jQuery just to use a third-party library, there’s some projects where I don’t want to load a large framework and wouldn’t mind only supporting modern browsers.

  9. You forgot one important thing : a lot of people like me just “use jquery” to avoid learning the DOM API.

    I’m a backend developper, forced to do front end work from time to time. I aleardy know Python / Django / nginx compilation / varnish / using REDIS as cache and DB / Postgress or MySQL setup and tweaking / Scripting / automating deploiement / git and so on.

    The I have to learn new stuff every day. Now using jquery by default just save me from having to learn the DOM for some ko added to the page.

    In your pluging exemple, sure the guy could have done that manually. But the time for him to figure it out may be 5 minutes for you, but it’s probably 3 days of work for him. Like it would be for you to debug this tricky encoding problem on the server while it’ll take me 5 minutes.

    I think it’s better that he coded a jquery only version that nothing at all because he wouldn’t have the time for this.

    Don’t get angry at this, days have only 24 hours and coding is just a part of it. Even when being eager to learn new stuff, what YOU think is a priority may not be someone else’s.

  10. While I agree with most of what you say, I just want to add that some programmers want to build on jQuery even if it is not immediately indispensable because they hope to extend the script – add more features in future where jQuery may be facilitating.

  11. Very inspirational. It sounds like a lesson in juggling. When you are just learning it and are happy with 3 balls then use jQuery, and the more experienced you get, the more you juggle around with polyfills and vanilla javascript and go for best of breed.

    What’s your opinion on http://modernizr.com/ or http://www.google.com/chromeframe?quickenable=true&hl=en to support latest browser minus 1 ?

  12. @Sam – an no point do I say you should not use jQuery. My message is: to consider when you need it.

    If your front end skills are lacking, then use a library like jQuery to help you get the task done. If they’re not, and you’re comfortable with jQuery, I’d encourage you to keep learning and look at the source of jQuery to see what happens under the hood.

    It’s not what’s better particularly for me, but better suited to the problem, and *not* the way I solve the problem, but the solution offered to the client and the end user. If I’m working on mobile dominant project, I naturally tend towards no-libraries. If I’m building a large project, I’m likely to drop in libraries that make the work easier to manage.

    Unlike your situation where you’re forced to work on the occasional front end dev, I’m not forcing you to ditch jQuery. But I’d worry if someone is avoiding learning a particular technology and also having to work with it. That’s like your working with MySQL and trying to avoid learning about database optimisation, how indicies work, memory, etc – that would worry me.

    Either way, my word isn’t gospel, I’m sure you (all) will continue working with what works for today.

    (Wanted to add – just because I can: I’m not a “client side developer” – I’m a developer, the front or back doesn’t bother me – I’ve been programming on both sides in multiple languages for many, many years, so I might just take the same 5 minutes it takes you to debug on the server too!)

  13. There was a typo in the BBC if statement provided – you just missed out the quotes around the first of each comparator :)

  14. Cheers – updated.

  15. Excellent article Remy. I just want to point out that multiple arguments for document.body.classList.add/remove is quite recent and not implement in Firefox Nightly (neither in IE10 I suppose).

  16. FYI the link to ‘cutting the mustard’ isn’t valid:
    Returns a 404…

  17. Great post and I’ll be thinking more about this in future when I’m coding.

    My current position is that, whilst I’m happy using vanilla JS if I need to, I use jQuery by default because I’d rather use the time I’d need to spend creating a wrapper/polyfill for the native methods on something else. Even without that, the jQuery team can do a much better job of it than I ever could and their documentation is superb.

    Be interested to hear how jQuery 2 fits into this – it’s a much leaner version and needs a mustard cutting browser from what I’ve been able to determine. Combined with a custom build I’m guessing it’s probably in the same ball park as your min.js.

  18. Hey Remy–some great points here, thanks.

    Your point about requestAnimationFrame versus setInterval (dropping frames) is right on, but I think your conclusion is a bit too hasty. My working solution is to use Cory Frang’s rAF jquery library, which substitutes the standard timer loop with rAF where supported. It’s new, well maintained, and only 2k:


    This gives super deep browser support, ultra convenient syntax, support for promises, etc etc. (It was originally in jq 1.6.1 but was pulled because people weren’t writing their callbacks intelligently, so now it lives on in plugin form.)

    Also, a general point: CSS animations are great for only the simplest of canned effects on the latest browsers. I think you’re overstating their usefulness for complex programmatic animations in a production environment.

  19. I have been working on similar lines! Check out http://h3manth.com/new/blog/2013/power-of-vanilla-js/

  20. Only to say that’s if you go to the doc there is a huge difference between $(‘input’).val() and $(‘input’).prop() ….
    jQuery is as light as simple… Use it everywhere, this is good for everyone to share their code… without re-inventing the wheel…

  21. Hey Remy,

    After reading your article I was curious what jQuery functions I used. So I created my own jQueryFunctionsFinder.
    I’m trying to come up with alternatives for my jQuery use. Also not to reinvent the wheel, though a little, but for getting a little deeper in Javascript.

    I havn’t tested it fully, but it works on the projects I tested it.

    Thanks for activating me!

  22. Thanks for talking about jQuery Animate Enhanced & Transit. I was looking for something like this.

  23. Very good article. Learnt a lot of new things which I never knew before.

  24. Congratulations for the post, Remy, it definitely made me rethink some aspects of my coding. But let me show you my point of view. jQuery have very “human” syntax and makes it easy to enter the world ot JavaScript and just make stuff work, without bothering about browser compatibility. Job gets done faster and quicker. Once you get used to jQuery it becomes a habit, kind of a second nature. When your boss tells you “this feature have to be done tomorrow” you find a plugin, add it and voalah – it works. You add more and more plugins, because it is easy. And a lot of front-end developers don’t know, or don’t care about how heavy the website becomes.

    I come from Flash background ( some serious AS3 coding ) and one thing I learned was that if you need very good performance, you have to write the code yourself – to left only the code you need and trim everything unnecessary, know what you can native feature you can use and what third party library you need. And I think that’s what makes the difference between front-end-dev and good-front-end-dev.

  25. Thanks for the article. I’ve been using Jquery more than JavaScript but I see more of a need to learn the robust language first before moving into JQuery.

  26. Daniel Wabyick May 30th, 2013 at 9:02 pm

    Great article. Another point is how slow JQuery is compared to straight DOM functions. For example … http://jsperf.com/jquery-css-vs-native-dom

    I will agree that the syntactic sugar for JQuery selectors and assignments is really nice. Are there any libraries, aimed at modern browsers, that provide the syntax shortcuts without the massive perf hit?

    Even better – are there any ‘cross-compiler’ solutions (like Coffeescript) that allow for clean syntax but cross-compile to native DOM calls? That would be right nice. ;-)

  27. Vlad Yanchevsky June 8th, 2013 at 7:19 pm

    Better way:
    Node.prototype.on = Node.prototype.addEventListener;

    This way allows you to call .on method for all HTML instances. Even for document ;)

  28. Nice – I’ll be changing the min.js project based on that.

Leave a Reply
Not required

CODE: Please escape code and wrap in <pre><code>, doing so will automatically syntax highlight