4

I'm trying to select the first child of a parent element with pure JavaScript and change some of it's CSS properties. I've tried .firstChild and .childNodes[1] methods but they do not work. This can be done with CSS nth-child() selector but I would like to do it with JavaScript for better browser support.

Example:

HTML

    <div class="daddy">
       <div class="child">I want select this child and change it's css property.</div>
       <div class="child"></div>
       <div class="child"></div>
       <div class="child"></div>
    </div>

What I've tried:

JavaScript

    var x = document.getElementsByClassName('daddy');
    var d = x.firstChild; // and the x.childNodes[1]
    d.style.width="5em";

What works:

CSS

   daddy:nth-child(1) { width: 5em; }

Any help will be appreciated.

Hashem Qolami
  • 97,268
  • 26
  • 150
  • 164
basitmate
  • 81
  • 2
  • 9

5 Answers5

7

Two problems:

  1. getElementsByClassName returns an array-like object. You need to select the first element in the list.
  2. firstChild and childNodes will return text nodes, not just elements. Use .children to access elements only:

var x = document.getElementsByClassName('daddy');
var d = x[0].children[0];
d.style.width="5em";
<div class="daddy">
  <div class="child">I want to select this child and change its css property.</div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
</div>
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
  • Thank you but can I use `document.getElementById()` instead of the `document.getElementsByClassName()`? Will it be the same code below? – basitmate Oct 10 '14 at 22:37
  • If your container *has* an ID, then yes - but in that case, you'll get a single element (not a list), so it would be `var d = x.children[0];` – Paul Roub Oct 11 '14 at 13:38
2
var x = document.getElementsByClassName('daddy');
var d = x[0].children[0];
d.style.width = '5em';

Or if you had multiple daddy elements you could do

var x = document.getElementsByClassName('daddy');

[].forEach.call(x, function(d) {
    d.children[0].style.width = '5em';
});
mildog8
  • 2,030
  • 2
  • 22
  • 36
1

for better browser support as you asked you can use pure CSS by using :first-child selector, since it is cross-browser and it is CSS 2.1, please see this link here and the table below that illustrates the browser support :

table first-child

so here is a snippet with CSS ONLY:

.child:first-child {
  /*whatever CSS you want here --
  just fot visualization and snippet :*/
  background-color: red;
  color: white;
}
<div class="daddy">
  <div class="child">I want select this child and change it's css property.</div>
  <div class="child">child 2</div>
  <div class="child">child 3</div>
  <div class="child">child 4</div>
</div>
dippas
  • 58,591
  • 15
  • 114
  • 126
  • Yes I know that `:first-child` will work quite well but what if I want to do this with JavaScript only? – basitmate Oct 10 '14 at 22:14
  • why would you want this JS only when you could have a easiest/cleanest solution by using CSS only like my answer? – dippas Oct 10 '14 at 22:16
  • I agree and I will be using `:first-child` but I'm just curious to know if this can be done with Js. – basitmate Oct 10 '14 at 22:33
  • you have a few answers with JS only already.. but since you are going to use the `:first-child` would you mark my answer as accepted? – dippas Oct 10 '14 at 22:38
  • 1
    Sure. May I ask what good it would do to you if I mark your answer as accepted? I'm new here. – basitmate Oct 10 '14 at 22:40
  • It only increases my reputation here in SO, but I said that because you told you we're going to use my answer, usually OP mark as accepted the answer that fixes the problem or the answer that OP he is going to use in his/her code ;) – dippas Oct 10 '14 at 22:43
0

getElementsByClassName returns a nodeList, it doesn't have firstChild or childNodes property, you should get the elements of the collection and then use those properties, i.e. x[index].

var x = document.getElementsByClassName('daddy'), i = 0, j;

for (; i < x.length; i++) {
    e = x[i].childNodes;
    for (j = 0; j < e.length; j++) {
        if (e[j].nodeType === 1) {
            e[j].style.width = '5em';
            break;
        }
    }
}

Please note that only newer browsers(including IE9) support the getElementsByClassName method. If you want to support the older browsers you should either shim the method or use an alternative function. Answers of this question provide several solutions.

As an alternative you can also use the querySelectorAll method:

[].slice.call(document.querySelectorAll('.daddy > .child:first-child'))
        .forEach(function(e) {
            e.style.width = '5em';
        });
Community
  • 1
  • 1
Ram
  • 143,282
  • 16
  • 168
  • 197
-2

IMO you should be using this: .daddy > .child

The difference between the standard X Y and X > Y is that the latter will only select direct children.

Please refer to this:

Hashem Qolami
  • 97,268
  • 26
  • 150
  • 164
FreddyNoNose
  • 478
  • 1
  • 7
  • 13
  • What does this have to do with the question? OP isn't looking to refine a CSS selector, nor is `.daddy .child` used anywhere in the question. – Paul Roub Oct 10 '14 at 21:40
  • All the `.child` elements are direct children of the `.daddy` element; this will do nothing to help find (only) the first child. – David Thomas Oct 10 '14 at 21:40