d3.selectAll returns a selection. You can get each of the elements by navigating through the array in the _groups property. When you are determining the width of a rectangle, you can use its index to get the corresponding text element:

.attr('width', function (d, i) {
    var textSelection = d3.selectAll('text');
    return textSelection._groups[0][i].getComputedTextLength();

The _groups property of d3's selection has a list of nodes at [0]. This list contains all of the selected elements, which you can access by index. It's important that you get the SVG element so that you can use the getComputedTextLength method.

You may also want to consider creating the rect elements first, then the text elements, and then going back to the rectangles to edit the width attribute, so that the text elements are on top of the rectangles (in case you want to fill the rectangles with color).


It's typically preferred that you don't access _groups, though, so a safer way to get the matching text element's width would be:

.attr('width', function (d, i) {
    return d3.selectAll('text').filter(function (d, j) { return i === j; })

Using node safely retrieves the element, and filter will find the text element which matches index.


You can use getBoundingClientRect()


.style('top', function (d) {
     var currElemHeight = this.getBoundingClientRect().height;

edit: seems like its more appropriate for HTML elements. for SVG elements you can use getBBbox() instead.


I would make the length part of the original data:

var nodesText = svg.selectAll("text")
       .text(function(d) {
      .attr("x", function(d, i) {
            return i * (w / dataset.length);
      .attr("y", function(d) {
            return 45;
      .each(function(d) {
        d.width = this.getBBox().width;

and then later

var nodes = svg.selectAll("rect")
        .attr("width", function(d) { return d.width; });

Related Query

More Query from same tag