Writing code is only one small piece of being a developer. In order to be efficient and capable at our jobs, we must also excel at debugging. When I dedicate some time to learning new debugging skills, I often find I can move much quicker, and add more value to the teams I work on. I have a few tips and tricks I rely on pretty heavily and found that I give the same advice again and again during workshops, so here’s a compilation of some of them, as well as some from the community. We’ll start with some core tenets and then drill down to more specific examples.
Main Concepts
Isolate the Problem
Isolation is possibly the strongest core tenets in all of debugging. Our codebases can be sprawling, with different libraries, frameworks, and they can include many contributors, even people who aren’t working on the project anymore. Isolating the problem helps us slowly whittle away non-essential parts of the problem so that we can singularly focus on a solution.
Some of the benefits of isolation include, but are not limited to:
- Figuring out if it’s actually the root cause we think it is or some sort of conflict
- For time-based tasks, understanding whether or not there is a race condition
- Taking a hard look at whether or not our code can be simplified, which can help with both writing it and maintaining it
- Untangling it and seeing if it’s one issue or perhaps more
It’s very important to make the issue reproducible. Without being able to discern exactly what the issue is in a way where you can reproduce it, it’s very difficult to solve for it. This also allows you to compare it to working model that is similar so that you can see what changed or what is different between the two.
I have a lot of different methods of isolation in practice. One is to create a reduced test case on a local instance, or a private CodePen, or a JSBin. Another is to create breakpoints in the code so that I can see it execute bit by bit. There are a few ways to define breakpoints:
You can literally write debugger;
inline in your code. You can see how this will fire small pieces at a time.
You can take this one step further in Chrome DevTools and even walk through the next events that are fired or choose specific event listeners:

Good ‘ol console.log
is a form of isolation. (Or echo
in PHP, or print
in python, etc…). You are taking one tiny piece of execution and testing your assumptions, or checking to see if something is altering. This is probably the most time-tested form of debugging, that no matter how advanced you become, still has its uses. Arrow functions in ES6 have allowed us to step up our console debugging game as well, as it’s now a lot easier to write useful one-liners in the console.
The console.table
function is also a favorite tool of mine, especially great for when you have a lot of data you need to represent- large arrays, large objects and the like. The console.dir
function is also a nice alternative. It will log an interactive listing of an object’s properties.

Be Methodical
When I teach workshops and help students in my class, the number one thing that I find holds them back as they try to debug a problem is not being methodical enough. This is truly a tortoise-and-the-hare kind of situation. They understandably want to move quickly, so they change a ton of things at once, and then when something stops working, they don’t know which thing they changed is causing the error. Then, to debug, they change many things at once and get a little lost trying to figure out what is working and what isn’t.
We all do this to some extent. As we become more proficient with a tool, we can write more and more code without testing an assumption. But if you’re new to a syntax or technology, being slow and careful behooves you. You have a much better shot at backing out of an issue you might have inadvertently created for yourself. And indeed, once you have created an issue, debugging one thing at a time might seem slower, but exposes exactly what changes have happened and where the error lies in a way that a seemingly faster pace doesn’t allow. I say seemingly because the time isn’t actually recovered working this way.
Do you remember when you were a kid and your parents said, “if you get lost, stay where you are?” My parents did, at least. It’s because if they were moving around to find me and I was also moving around to find them, we’d have fewer chances of bumping into one another. Code works the same way. The less moving pieces you have, the better- the more you are returning consistent results, the easier it will be to track things down. So while you’re debugging, try not to also install anything, or put in new dependencies. If you see a different error every time you should be returning a static result, that’s a big red flag you should be headed right for with your sleuth hat on.
Choose Good Tools
There are a million different tools for solving a variety of problems. I’m going to work through some of the tools I find the most useful and then we’ll link off to a bevy of resources.
Syntax Highlighting
Sure, it’s damn fun to pick out the new hotness in colors and flavors for your syntax highlighting theme, but spending some time thinking about clarity here matters. I often pick dark themes where a skip in syntax will turn all of my code a lighter color, I find errors are really easy to see right away. I tend to like Oceanic Next or Panda, but really, to each their own on this one. It’s important to keep in mind that when looking for a good syntax highlighter, awesome-looking is great, but functional for calling out your mistakes is most important, and it’s totally possible to do both.
Linting
Linting helps flag suspicious code and calls out errors we might have overlooked. Linting is incredibly important, but which linter you choose has so much to do with what language/framework you’re writing in, and then on top of that, what your agreed-upon code style is.
Different companies have different code styles and rules. Personally, I like AirBnB’s, but take care and don’t just use any old linter. Your linter enforces patterns that, if you yourself don’t want to enforce, can stall your build process. I had a CSS linter that complained whenever I wrote a browser hack, and ended up having to circumvent it so often that it stopped being useful. But a good linter can shine light on small errors you might have missed that are lurking.
Here are some resources:
- I recently found this responsive images linter, that tells you what opportunities you might have to use picture, srcset, or sizes.
- Here’s a pretty good breakdown of some JS linters
Browser Extensions
Extensions can be really awesome because they can be enabled and disabled so readily, and they can work with really specific requirements. If you’re working with a particular library or framework, chances are, having their extension for DevTools enabled is going to give you all sorts of clarity that you can’t find otherwise. Take care though- not only can extensions bog a browser down, but they have permissions to execute scripts, so do a little homework into the extension author, ratings, and background. All that said, here are some of my favorites:
- Accessibility extension from Dequeue Systems
- React DevTools really vital, in my opinion, if you’re working with React, to see their virtual DOM
- Vue DevTools same endorsement as above.
- Codopen: pops you out of the editor mode into a debug window for CodePen. Full disclosure: my husband made this for me as a present because he was sick of watching me manually opening the debug window (best gift ever!)
- Pageruler: get pixel dimensions and measure anything on a page. I like this one because I’m super duper anal about my layout. This helps me feed the beast.
DevTools
This is probably the most obvious of debugging tools, and there are so many things you can do with them. They can have so many packed-in features that can be easy to miss, so in the next section of specific tips, we’ll go into a deep dive of some favorites.
Umar Hansa has great materials for learning what the DevTools can do. He has a weekly newsletter and GIFs, a new course linked in the last section, and an article on our site.
One of my favorite recent ones is this CSS Tracker Enhancement, shown here with permission from Umar. This shows all of the unused CSS so that you can understand the performance impact.

Misc Tools
- What input is a global utility for tracking the current input method (mouse, keyboard or touch), as well as the current intent- this can be really good for tracking down accessiblity leaks (hat tip to Marcy Sutton, accessibility expert for this tipoff)
- Ghostlabapp is a pretty snazzy tool if you’re doing responsive development or checking anything deployed across a ton of devices. It offers synchronized web development, testing, and inspection.
- Eruda is an awesome tool that helps debug on mobile devices. I really like it because it takes a simulator a step further, gives a console and real devtools to help you gain understanding.

Specific Tips
I am always interested in what other people do to debug, so I asked the community through the CSS-Tricks account and my own what they were really into. This list is a mixture of tips I like as well as a roundup of tips from the community.
Accessibility
$('body').on('focusin', function() {
console.log(document.activeElement);
});
This logs the currently focused element, useful because opening the Devtools blurs the activeElement
Debugging CSS
We got quite a lot of responses saying that people put red borders on elements to see what they’re doing
@sarah_edo for CSS, I'll usually have a .debug class with a red border that I slap on troublesome elements.
— Jeremy Wagner (@malchata) March 15, 2017
I do this too, I even have a little CSS file that drops in some classes I can access for different colors easily.
Checking State in React
@sarah_edo <pre>{JSON.stringify(this.state, null, 2)}</pre>
— MICHAEL JACKSON (@mjackson) March 15, 2017
Props to Michael, this is one of the most useful debugging tools I know of. That snippet “pretty prints” the state of the component you’re working with onto the component so that you can see what’s going on. You can validate that the state is working the way that you think it should be, and it helps track down any errors between the state and how you’re using it.
Animation
We got a lot of responses that said they slow the animation way down:
@sarah_edo @Real_CSS_Tricks * { animation-duration: 10s !important; }
— Thomas Fuchs (@thomasfuchs) March 15, 2017
I mentioned this on a post I wrote right here on CSS Tricks about debugging CSS Keyframe animations, there are more tips too, like how to hardware accelerate, or work with multiple transforms in different percentages.
I also slow down my animations in JavaScript- in GreenSock that would look like: timeline.timeScale(0.5)
(you can slow down the whole timeline, not just one thing at a time, which is super useful), in mo.js that would look like {speed: 0.5}
.
Val Head has a great screencast going through both chrome and firefox devtools offering on animation.
If you want to use the Chrome Devtools timeline to do performance audits, it’s worth mentioning that painting is the most expense of the tasks, so all things being equal, pay a little more attention to a high percentage of that green.
Checking different connection speeds and loads
I tend to work on fast connections, so I will throttle my connection to check and see what the performance would look like for people who don’t have my internet speed.

This is also useful in conjunction with a hard reload, or with the cache empty
@sarah_edo Not so secret trick. But still many people are unaware. You need DevTools open, and then right click over the refresh button. pic.twitter.com/FdAfF9Xtxm
— David Corbacho (@dcorbacho) March 15, 2017
Set a Timed Debugger
This one came from Chris. We have a whole writeup on it right here:
setTimeout(function() {
debugger;
}, 3000);
It’s similar to the debugger; tool I mentioned earlier, except you can put it in a setTimeout function and get even more fine-tuned information
Simulators
@Real_CSS_Tricks And just in case any Mac users didn't know this, iOS simulator + Safari is sweet. pic.twitter.com/Uz4XO3e6uD
— Chris Coyier (@chriscoyier) March 15, 2017
I mentioned simulators with Eruda before. iOS users also get a pretty sweet simulator. I was going to tell you you have to install XCode first, but this tweet showed another way:
@chriscoyier @Real_CSS_Tricks Or, you can use this approach if you didn't want to bother with installing xCode: https://t.co/WtAnZNo718
— Chris Harrison (@cdharrison) March 15, 2017
Chrome also has a device toggle which is helpful.
Remote Debuggers
@chriscoyier @Real_CSS_Tricks https://t.co/q3OfWKNlUo is a good tool.
— Gilles 💾⚽ (@gfra54) March 15, 2017
I actually didn’t know about this tool until seeing this tweet. Pretty useful!
CSS Grid Debugging
Rachel Andrew gave a presentation at Smashing and mentioned a little waffle thing you can click on in Firefox that will illuminate the gutters in the grid. Her video explains it really eloquently.

Array Debugging
Wes Bos with a really useful tip for searching for a single item in an array:
If you are just looking for a single item array.find() is 🔥 https://t.co/AuRtyFwnq7
— Wes Bos (@wesbos) March 15, 2017
Further Debugging Resources
Jon Kuperman has a Frontend Masters course that can help you master devtools it goes along with this app.
There’s a small course on code school called discover devtools.
Umar Hansa has a new online course called Modern DevTools.
Julia Evans has a great article about debugging here, hat tip to Jamison Dance for showing it to me.
Paul Irish does some advanced performance audits with devtools if you’re super nerdy like me and want to dig into the timeline.
Finally, I’ll put in a bittersweet resource. My friend James Golick who was an excellent programmer and even more excellent human gave this great conference talk about debugging anything many years ago. Sadly James has passed, but we can still honor his memory and learn from him:
For debugging css, I found this extension a while back. find it very useful. Pesticide for chrome. puts colored borders on elements so you can see where they all are.
https://chrome.google.com/webstore/detail/pesticide-for-chrome/bblbgcheenepgnnajgfpiicnbbdmmooh
Hi Keith, Nice extension.
A collage of mine wrote this: https://github.com/srambach/classbxr
It’s not an extension but it does the same and it also shows class names.
You mentioned a React debugger in the article so I thought I would also toss in one for Angular – Augury. It’s a Chrome extension that helps debug Angular apps. It’s one drawback is that It is limited to Chrome.
Great post Sarah! I find that devs overlook the power of Devtools. Granted, it has come a very long way, but I find it’s the 1st line of debugging, detection of smoke – before the fire . And all are using the actual browser, but somehow never opt-cmd i. ;)
Adding the idea of remote debugging in Chrome DevTools when you tether an Android phone to see actual mobile issues, just a step past throttling on a desktop and device toolbar’ing.
Using a real border for CSS debugging can be a problem, as the border has a width, and thus may have an impact on the layout.
Basically I use a fake border, either using outline or box-shadow. They have the advantage that they have no impact on the rest of the layout, and just give the desired element a highlight.
You can solve this problem with box-sizing:
These tips help me a lot, thanks for sharing!
Thank you Sarah!
Lots of good insights.
The idea to ask the community is very cool.
One of the most powerful tools for debugging any C-like language (like JavaScript) is use of assert. In fact, the language Eiffel was developed largely to make the use of asserts (contracts, in Eiffel-speak) a central feature of the language.
A good, simple example of an assert function is given here. Typical use would be (if not using TypeScript) to check the type of arguments being passed to a function. By checking that your assumptions are valid, you can discover cases where they aren’t rather than waiting until the problem becomes visible.
Isn’t that essentially just Unit Testing?
cu, w0lf.
Appendix: Or maybe classic A/B testing?
cu, w0lf.
Unit testing is just a generic term for testing a module to make sure it works, and typically is done after coding is complete. Asserts are written as part of the code to anticipate possible points of failure and ensure that failure doesn’t happen, or if it does, that it is caught early. Typically, assert code is written so that it does nothing in production and is only executed in the test environment. Thus the assert code always remains in place. This means that if some future modification breaks the assumptions, the error will be caught.
The biggest issue people have with dev tools is they don’t know how to get the result they want. Yeah, you can set breakpoints, but how does that make it easier to fix my bug?
I’ve set a breakpoint and reloaded the page. What now? Which button makes things happen? How does all this info help me fix a bug? People know some tools exist, but they’re so freaking complicated, so most use console.log debugging instead.
It’s hard to apply the different features if you don’t know how they work together. I wrote some step by step examples about how you can approach debugging some real’ish bugs using the dev tools, showing how it all comes together which hopefully makes it easier to understand how to use it to solve your own problems too:
https://codeutopia.net/blog/2015/11/01/how-to-fix-javascript-errors-more-easily-with-chromes-debugger/
That’s a great intro to dev tools Jani, wish I had read that a couple of years ago! ;)
With CSS i used to use border, but I have increasingly used outline instead, as it does not add pixels to the box model slight problem with it though, it does not always show on all edges depending on display types and other voodoo insofar as I can tell.
Another resource readers might find useful. Wrote up my methodology for CSS debugging around a year ago. https://benfrain.com/debugging-css/
Shares a lot of the same ideas, particularly with regards isolation and replication.
There are links to Russian and Chinese versions there too. :)
Must have tool… http://www.sprymedia.co.uk/article/visual+event+2
In testing web-app of https://crossbrowsertesting.com/ (for some browser-device combos) there’s a debugger button which opens the dev tools ️
https://twitter.com/TobiReif/status/854284095391756288
No mention of sourcemaps whatsoever?
We live in a time where our code gets compiled/merged/minified/obfuscated multiple times using various pre-processors & compilers. Not using sourcemap to have access to the original source code/line number, would make it really hard to isolate any issues. Even with all the tools mentioned here.
Webpack, for example has a
devtool
option to enable sourcemaps.https://webpack.js.org/configuration/devtool/
And individual loaders also has options to create sourcemaps after your code has been processed by them.
https://github.com/postcss/postcss-loader#sourcemaps
https://github.com/webpack-contrib/sass-loader#source-maps
Another tips, for production code we use error tracking service like Sentry. these services logs and notifies you for any issues caught by your users. Along with details of the error, like stack trace, browser version, page URL, etc.
Another altenative is TrackJS. Also useful. these things are like Google Analytics for errors.