Find element with class and append div without jQuery

jQuery is a wonderful library that allows you to achieve cross browser support a lot more easily than writing with pure Javascript as well as making it relatively straight forward to traverse and update the DOM. Sometimes, however, the project you are working on will not have jQuery available so you are faced with the question: Do I include jQuery for this small bit of fuctionality, or, do I learn how to write it with vanilla Javascript?

This is precisely the issue that I was facing with the secondary sidebar navigation on this site as part of the redesign. The team at No Divide provided me with clean semantic markup for the navigation, and the enhanced version used Vue.js for the interactivity — no jQuery to be found anywhere.

Here is the mark up:

<ul class="nav__items">
  <li class="nav__item">
   <a href="#" class="nav__link active">Responsive HTML</a> 
    <div class="nav__expand"><span class="icon icon--down-arrow"></span></div> 
     <ul class="nav__child-items">
      <li class="nav__child-item">
       <a href="#" class="nav__child-link">Am I responsive?</a>
      <li class="nav__child-item">
       <a href="#" class="nav__child-link">Viewport meta element</a>
    <li class="nav__item"><a href="#" class="nav__link">CSS</a> //etc etc

Each li for the nav has a class of .nav__item, and if that has any child elements there is also a div added with the class .nav__expand and a span for the toggle icon.

From there is the next ul for the sub list along with the li‘s and links as well.

For anyone that has every used WordPress (or any slightly opinionated CMS) will know all too well that the markup you would like to use and the markup that is generated by WordPress will not always match.

The markup provided by the wp_list_pages() function in wordpress comes packed with a whole bunch of default classes which is never likely to match up with something BEM focussed. If you’re working with a team that delivers WordPress sites a lot you’ll likely get something that matches the output of WordPress, however, I don’t think this is necessarily a good thing. If at some point you want to migrate from one CMS to another you’re porting a set of markup that is irrelevant. I’m all for doing things the right way and using a CMS that isn’t opinionated (something like Craft I’ve been told) or manipulating WordPress in a way that delivers what you need.

Here’s the wordpress code out of the box:

<ul class="nav__items">
  <li class="page_item page-item-931 page_item_has_children">
   <a href="">CSS</a>
    <ul class='children'>
     <li class="page_item page-item-936">
      <a href="">CSS3 Multiple Columns</a>
  <li class="page_item page-item-941"><a href="">How do I organise my CSS?</a></li>
<li class="page_item page-item-932"><a href="">Frameworks</a></li>

I’m sure there is likely to be a function that could be written and added to the functions.php file to manipulate the output, and I would encourage tweets in reference to how to do that, but for now this is what I’m having to work with (and I’m guessing a lot of you as well).

In the end I went back to the CSS, took the styles applied via the BEM method and reapplied them to a javery_overrides.scss file. This solved the issue with the class names, but it didn’t solve the issue of the<div class="nav__expand">....</div> issues.

The jQuery way

I’m not great at Javascript but I’ve become more and more comfortable when dabbling with jQuery over the years. First I had to target the instances where the .page_item_has_children was found, and the a directly following it.

$('.page_item_has_children_jquery > a')

Once I found all those I just had to add in the additional markup by using .after('//div I need here').

$('.page_item_has_children_jquery > a').after('<div class="nav__expand"><span class="icon icon--down-arrow"></span></div>');

That took about 5 minutes for me to get sorted (maybe even less).

Alas, though, there was no jQuery included on the project and I didn’t want to load up the whole script just so I could achieve that small piece of funtionality. Of course, there is native JS shipped with everything these days….

The Javascript way

let x = document.body.querySelectorAll('.page_item_has_children > a');
 let index = 0;
 for( index=0; index < x.length; index++ ) { var navArrow = document.createElement('div'); navArrow.className = 'nav__expand'; navArrow.innerHTML = '<span class="icon icon--down-arrow"></span>';
      x[index].parentNode.insertBefore(navArrow, x[index].nextSibling);   

To Javascript, or to jQuery

My Javascript is certainly not one of my strong points, and in fact, could be considered the weakest area of my skill set. Even so, it wasn’t that difficult to take a straight forward jQuery approach to this problem and make it work using Javascript alone.

The next time you feel yourself reaching for jQuery, or any Javascript library for that matter, I encourage you to spend a few minutes to see if what you’re trying to achieve could be done just as easily without the library.

If you would like a few more basic things you can do then check out You Might Not Need jQuery For That

Subscribe to our Newsletter

Add your email address and receive an email every Friday covering off everything worth knowing about building your websites responsively.