Edit: Point of clarificatioon, IDs and classes as separate hooks is just one form of the applied idea in question which is to never use the same hooks for CSS as you do in JS. I've also seen people want things like js-combo_box and css-combo_box as classes on the same element.

This is one I've started running into more and more in recent years. People wanting to only use IDs for JS and classes for CSS. Or they don't want JS to touch classes and IDs at all and rely on things like HTML5 data-attributes hooks (which is and will probably remain the slowest way to actually find an element even in modern browsers).

In 5+ years of occasionally heavy-duty/insane-environment client-side web development including one very large totally messed up e-commerce retail operation where HTML nobody was even working with would mutate because we had 200 offshore devs of varying levels code illiteracy (completely on the low end, not kidding) jumping up and down on the back end codebase with no source control, I've never run into an issue where JS and CSS targeting shared attributes in the HTML caused any kind of maintainability or ease of modification problem for me. I guess I'm wondering what is informing this perceived need and whether I'm missing something that comes up for a lot of people?

Isn't HTML via selectors and the DOM API effectively the point of abstraction that ties everything together? Why would JS and CSS concerns sharing the same attributes there ever cause a problem?

  • There isn't one. I think you're coming at this from the wrong angle... – Izkata Mar 8 '13 at 1:17
  • 1
    Actually, rereading your question, the answer I started typing up doesn't seem to quite match the question. Now I just think those people you're referencing are idiots/uninformed. (Simplification of code can create what appears to be what you describe between IDs and Classes, but searching based on data attributes is just weird...) – Izkata Mar 8 '13 at 1:30
  • Don't some of the newer MV<you-pick> frameworks follow this philosophy? – Erik Reppen Mar 8 '13 at 1:34
  • And then there's this guy. stackoverflow.com/questions/8084555/… But really I just want to find if there's some influential source of what I suspect to be kool aid because it keeps popping up occasionally. – Erik Reppen Mar 8 '13 at 1:49
  • Probably an attempt at separation of concerns, and possibly to lower the bar for who gets to edit HTML – Phil Lello Mar 9 '16 at 22:42

Maybe you notice that because, as you said it yourself, you have to work with inexperienced programmers.

In practice, the distinction you observe doesn't exist. Frameworks, by the way, discourage such distinction.

For example, jQuery encourages pretty well to use selectors in a general way, which means that you use IDs to target a single element and classes to target multiple elements.

In the same way, a not totally retarded developer would quickly notice (learn) that classes are bad candidates for unique elements on a page: of course, you can replace all IDs by classes in both HTML and correspond CSS, but it would make things slightly... let's say unreadable, if nobody cares about performance.

As for the inexperienced programmers, they may tend to do strange things. It took me a few weeks to explain to one fellow colleague that:

<div id="entry">Some text here</div>
<div id="entry">Some other text</div>

is wrong, because IDs are unique. Take one beginner who have just read an article explaining how to use classes in CSS and another article about data- attributes in jQuery, and you easily understand why this beginner starts to use classes for CSS and data- for jQuery selectors.

  • 1
    +1, but I'm not convinced by your point about not using classes. I'd say performance is not really a problem, and readability either. I ended up using classes for almost everything, because I have little controll over ids. In AJAX heavy sites, ids tend to be somewhat dangerous (as they get non-unique very fast, if you aren't careful). – Bruno Schäpper Mar 8 '13 at 5:40
  • @VainFellowman You should have control over IDs if your domain is the client-side but I've been in that situation (webforms maybe?). I don't think I'd fault sombody for classing unique elements because some heavy-handed server-side shenanigan was hogging them for it's own pointless tight coupling to the back-end. I would however, still try to ID unique containers on a page whenever possible to at least reduce the amount of work class selectors have to do by narrowing down to those containers. – Erik Reppen Mar 8 '13 at 15:48
  • @MainMa It has been striking to me that a lot of the newer MVetc... frameworks seem to do their damnedest to bind to things other than classes and IDs like data and custom attributes, however. It's starting to seem like there's this subconscious undercurrent that occasionally surfaces as a blog post here and there and manifests in frameworks but I can't find anybody particularly outspoken/influential on the subject. – Erik Reppen Mar 8 '13 at 16:02
  • 2
    @Erik Reppen: do you have any particular frameworks in mind? By the way, web frameworks in general are really strange: some, like CodeIgniter, are encouraging best practices, while others, like classical ASP.NET, are criticized for doing terrible things when it comes to clean HTML code and proper use of IDs and other attributes. – Arseni Mourzenko Mar 8 '13 at 16:08
  • Sorry, should have specified that I meant the MV(?) client-side-specific frameworks like Angular, Ember, Knockout, etc... – Erik Reppen Mar 8 '13 at 16:13

Using classes for JS makes perfect sense.

Classes, like their name suggests classify DOM elements.

For example, if I had a list of items

<div class='item'>Item1</div>
<div class='item'>Item2</div>
<div class='item'>Item3</div>
<div class='item'>Item4</div>

It would make perfect sense to select them with the following selector .item instead of assigning an ID to each of them.

More-over, in many commonly used JavaScript libraries and code bases class selectors are used for selecting elements. I've seen it used in production code many times and it seems like acceptable practice.

The only beef people have with class selectors over ID selectors is that ID selectors are faster (perf here). Most of the time I have found that doesn't really matter.

  • Thanks. Agreed on the perf thing. In this case I've been more of the understanding that it was architectural concern of some sort. – Erik Reppen Mar 8 '13 at 2:17

Okay, a complete flip-flop of what I was going to write, based on two specific parts of the question:

we had 200 offshore devs of varying levels code illiteracy (completely on the low end, not kidding)


Why would sharing attributes there ever cause a problem?

I have run across something similar to this in the project I'm on at work right now. What I was dealing with is what happens when the unskilled programmers tie functionality entirely to classes, without thinking about consequences or maintainability. (That is, they were reusing classes just because they're there and happen to be on all the right elements)

What you're looking at is a simple, sledgehammer-like way to enforce separation of concerns on the unskilled programmers.

If functionality is strictly tied to IDs, and design to Classes, then they can change both without having to worry about the other. This is especially helpful from a design standpoint - as long as they include all the requisite IDs for the Javascript functionality, they're fine.

That said, I strongly disagree with this approach (see other answers for why). It's extremely limiting to even the halfway-decent programmers and almost always requires extra bookkeeping javascript to keep track of #foo_1, #foo_2... when .foo would have sufficed.

EDIT @jmoreno has pointed out that I missed the clarification paragraph at the top, so now parts of my original answer seems much more appropriate. Personal anecdote time!

See, at work, we have a library written in Django+JS+CSS, shared among a large chunk of our products. It was written in a very specific way, meant to be highly configurable, and included into various projects by way of a Django templatetag with arguments used for configuration of the JS.

Unfortunately, because the JS and CSS was tied together by sharing classes, it meant that certain features that looked like entirely separate options could only work if both were specified, or both were left out. And they were mutually exclusive with a third. Any other combination caused the JS to error out, because it would make assumptions about which classes existed in the generated HTML.

We needed options 2 and 3, but not 1. This was unfortunate, to say the least: For example, Option 1 was including CSS-styled classes for Option 2's JS (which it was only using because, as described above, the classes were already there so why not?). So if you used Option 2 without Option 1, there would be so much breakage styling-wise that it became unusable.

I have been beating that JS into submission on and off for nearly three months at this point, just making all 3 options independent of each other and ironing out the bugs.

This extra work shouldn't have been necessary, and wouldn't have been if the whole thing was well-written initially. Forcibly separating which classes the JS and CSS act upon would have helped to prevent Option 1 and Option 2 from getting tied together back when it was first being written.

That said, it's generally not possible to be 100% on this rule. One of those is a simple .loading class that gets added/removed as necessary.

  • I suppose. I think I have seen people use #id_897502, #id_12098 in the CSS only to mysteriously break 5 days later when they could have just used #container .combo_box. Stuff like that seems like a level of stupidity/inexperience that you should be accounting for with best hiring rather than best coding practices though but I suspect we've both seen employers who got more than a couple things completely bass-ackwards. – Erik Reppen Mar 8 '13 at 2:24
  • @Izkata: the question says they use both id's and classes for javascript, but a class for javascript isn't to be used for CSS (enforced by naming conventions). So, while I agree they are doing this to seperate concerns, it may not be as bad as you think. I would also suggest this isn't just mitigation of risk, but allowing the seperate concerns to be worked on independently – jmoreno Mar 8 '13 at 3:15
  • @jmoreno Ah, the clarification paragraph seems to have been added while I was typing this answer, and I just missed it – Izkata Mar 8 '13 at 3:52
  • @jmoreno Check my edit... – Izkata Mar 8 '13 at 4:45
  • @Izkata: yeah, that was the kind of thing I was thinking about. It reminds me of the problem of coincidentally similar code -- code that is basically the same, with a few minor differences. You can develop a function that does both, but because they are only similar in expression not purpose, as requirements change the expressions diverge more and more. See the comment by Jason at ayende.com/blog/4333/effectus-isolated-features – jmoreno Mar 8 '13 at 6:03

As someone who’s adopted this pattern, one of the biggest reasons I’ve done it is that I feel it makes the markup a little more semantic. If I’m working on changes that touch an element with a .js- class on it I know that there should be some JS somewhere that is either listening to this element or operating on it. Knowing that the JS is using this element means that I’m extra careful about how I change it.

The same could be said about using a data attribute except that you could argue that it goes one step further by separating the JS from the CSS by not using id’s or classes(I don’t typically use data attributes as JS selectors but I’ve seen it).


First, I don't think that separation is absolute. id's for example are unique to a document and so it makes sense to use them for both CSS and JS. For classes though, there are good reasons for these to be separate.

The basic issue is that CSS and JS implement what you might think of as cross concerns. CSS implements layout, display, and typography, while JS implements behavior. Or at least this is how they are most often (and I think, best) used. You can think of these as orthogonal concerns or dimensions, and so individual DOM objects may need to be placed, not in a line of functionality, but rather in a two-dimensional area where the dimensions are display and functionality.

Again if you want to look up a single element, CSS and JS may both do this by ID, but if you want to look up a group you probably don't want to tie display and behavior together too tightly.

This is a general issue and I don't think it depends on how experienced your developers are or what tools you are using. As long as the concerns are different you may want to be able to classify elements according to multiple types of concerns and this is one way this happens.


In 2020, I will tend to do something like the following.

Imagine an accordion menu:

<nav class="mainMenu">

  <ul class="mainMenuList">

  <li class="mainMenuSection">
    <strong class="mainMenuSectionTitle">Site Section A</strong>
    <ul class="mainMenuPageList">
    <li class="mainMenuPage">Page A1</li>
    <li class="mainMenuPage">Page A2</li>

  <li class="mainMenuSection open" data-main-menu-section-state="open">
    <strong class="mainMenuSectionTitle">Site Section B</strong>
    <ul class="mainMenuPageList">
    <li class="mainMenuPage">Page B1</li>
    <li class="mainMenuPage">Page B2</li>
    <li class="mainMenuPage">Page B3</li>
    <li class="mainMenuPage">Page B4</li>

  <li class="mainMenuSection">
    <strong class="mainMenuSectionTitle">Site Section C</strong>
    <ul class="mainMenuPageList">
    <li class="mainMenuPage">Page C1</li>
    <li class="mainMenuPage">Page C2</li>
    <li class="mainMenuPage">Page C3</li>



(To clarify, data-main-menu-section-state="open" is the open section of the accordion, which, when opened by the visitor, unfurls downwards until all the links from Page B1 to Page B4 are fully revealed.)

The argument against this would be that, since both:

  • .open
  • data-main-menu-section-state="open"

indicate the accordion section which is open, only the first is necessary.

But, this kind of setup where:

  • classes represent CSS hooks; and
  • HTML5 Custom data-* attributes represent JS hooks

means I can have some confidence (not least if I am coming back to a project that I last worked on months before) that I can remove or change the name of any particular class when refactoring the document's Presentation and it will never disable any JS Behaviour currently applied to the same element.

Furthermore, I may deploy the generically-named class .open elsewhere in the document, leading to two similar but not identical style-blocks in my stylesheet, such as:

  • .mainMenuSection.open
  • .headerMenuSection.open

in full confidence that the new elements that I append the class .open to, won't then also immediately adopt javascript behaviour which I don't need or want them to have.

In Summary:

When I'm refactoring CSS, I don't want to also have to be constantly thinking about whether this is going to result in any unwanted javascript side-effects.

And when I'm refactoring JS, I don't want to also have to be constantly thinking about whether this is going to result in any unwanted CSS side-effects.

See also: Uncle Bob Martin's Single Responsibility Principle

Not the answer you're looking for? Browse other questions tagged or ask your own question.