D3 in Depth covers versions 6 and 7 of D3

Home About

D3 Selections

How to select HTML and SVG elements using D3 selections. This article shows how to select, insert, remove and modify elements, how to add event handlers, how to apply a function to selections and how to filter and sort selections.

D3 selections let you choose some HTML or SVG elements and change their style and/or attributes.

For example, if your index.html file contains 5 SVG circle elements:

<svg width="760" height="140">
<g transform="translate(70, 70)">
<circle/>
<circle cx="120" />
<circle cx="240" />
<circle cx="360" />
<circle cx="480" />
</g>
</svg>

you can use selectAll to select the circles then .style to change their fill and .attr to change their radius:

selectAll('circle')
.style('fill', 'orange')
.attr('r', function() {
return 10 + Math.random() * 40;
});

D3 selections also enable data joins (see the Data Joins chapter).

Making selections

The D3 module d3-selection provides two functions select and selectAll.

To import select use:

import { select } from 'd3-selection';

To import selectAll use:

import { selectAll } from 'd3-selection';

Import both using:

import { select, selectAll } from 'd3-selection';

select selects the first matching element whilst selectAll selects all matching elements.

Both functions take a string as its only argument. The string specifies which elements to select and is in the form of a CSS selector string. For example:

  • div.item
  • #my-chart
  • g:first-child

For example to select all elements with class item use:

selectAll('.item')

(If you’re not familiar with CSS selectors take a look at the CSS section in Fundamentals of HTML, SVG, CSS and JavaScript for Data Visualization.)

Modifying elements

You can modify a selection's elements using the following methods:

NameBehaviourExample
.styleUpdate the styleselectAll('circle').style('fill', 'red')
.attrUpdate an attributeselectAll('rect').attr('width', 10)
.classedAdd/remove a class attributeselect('.item').classed('selected', true)
.propertyUpdate an element's propertyselectAll('.checkbox').property('checked', false)
.textUpdate the text contentselect('div.title').text('My new book')
.htmlChange the html contentselect('.legend').html('<div class="block"></div><div>0 - 10</div>')

Note that the second argument of .classed is a boolean. I often forget to include true or false and it raises an non-obvious error message!

Here's an example of all of these functions in use:

Updating selections with functions

You can also pass a function into a selection method. For example:

selectAll('circle')
.attr('cx', function(d, i) {
return i * 100;
});

The function accepts two arguments. The first argument (usually named d) is the joined data (or 'datum') and will be covered in the data joins chapter. The second argument (usually named i) is the index of the element within the selection.

To update elements in a selection according to their position within the selection use the i argument. For example to position rect elements horizontally use:

selectAll('rect')
.attr('x', function(d, i) {
return i * 40;
});

In the majority of cases anonymous functions are passed into selection methods. However you may altenatively use named functions. For example:

function positionRects(d, i) {
return i * 40;
}

selectAll('rect')
.attr('x', positionRects);

Event handling

You can add an event handler to a selection using the .on method.

This method has two arguments:

  • the first is a string specifying the event type

  • the second is a function (a 'callback function') that's called when the event is triggered. This callback function has two arguments that are usually named e and d. e is the DOM event object and d is the joined data (which will be covered in the data joins chapter).

Up to and including D3 version 5, the callback function was passed the datum d and index i. This is a breaking change.

The most common events include:

Event nameDescription
clickElement has been clicked
mouseenterMouse pointer has moved onto the element
mouseoverMouse pointer has moved onto the element or its children
mouseleaveMouse pointer has moved off the element
mouseoutMouse pointer has moved off the element or its children
mousemoveMouse pointer has moved over the element

See MDN event reference for more details.

In the event callback function the this variable is bound to the DOM element that triggered the event. This allows us to do things such as:

selectAll('circle')
.on('click', function(e, d) {
select(this)
.style('fill', 'orange');
});

Note that this is a DOM element and not a D3 selection so if you wish to modify it using D3 you must first select it using select(this).

Note also that D3 does not define this for arrow functions.

Inserting and removing elements

Elements can be added to a selection's elements using .append and .insert. Elements can be removed using .remove.

.append appends an element to each element in a selection. If the elements already have children, the new element will become the last child. The first argument specifies the type of element.

As an example let's start with 3 g elements, each containing a circle:

<g class="item" transform="translate(0, 0)">
<circle r="40" />
</g>
<g class="item" transform="translate(120, 0)">
<circle r="40" />
</g>
<g class="item" transform="translate(240, 0)">
<circle r="40" />
</g>

Append a text element to each using:

selectAll('g.item')
.append('text')
.text('A');

This results in a text element being added to each g.item:

<g class="item" transform="translate(0, 0)">
<circle r="40" />
<text>A</text>
</g>
<g class="item" transform="translate(120, 0)">
<circle r="40" />
<text>A</text>
</g>
<g class="item" transform="translate(240, 0)">
<circle r="40" />
<text>A</text>
</g>

.insert is similar to .append but it lets us provide a CSS selector string as the second argument. This specifies an element before which the new element is inserted.

In this example, .insert is used and the second argument is 'circle':

selectAll('g.item')
.insert('text', 'circle')
.text('A');

This results in the text element being inserted before the circle:

<g class="item" transform="translate(0, 0)">
<text>A</text>
<circle r="40" />
</g>
<g class="item" transform="translate(120, 0)">
<text>A</text>
<circle r="40" />
</g>
<g class="item" transform="translate(240, 0)">
<text>A</text>
<circle r="40" />
</g>

.remove removes all the elements in a selection from the page. For example, given some circles, you can remove them using:

selectAll('circle')
.remove();

Chaining

The return value of most selection methods is the selection itself. This means that selection methods such as .style and .attr can be chained. For example:

selectAll('circle')
.style('fill', '#333')
.attr('r', 20)
.on('click', function(d, i) {
select(this)
.style('fill', 'orange');
});

.each()

The .each method lets you call a function for each element of a selection.

The callback function has two arguments usually named d and i. The first argument d is the joined data (or 'datum') and will be covered in the data joins chapter. i is the index of the element within the selection. The this keyword refers to the current HTML or SVG element in the selection.

Here's an example where .each is used to call a function for each of the selection's elements. The function computes whether the index is odd or even and modifies the circle accordingly:

selectAll('circle')
.each(function(d, i) {
let odd = i % 2 === 1;

select(this)
.style('fill', odd ? 'orange' : '#ddd')
.attr('r', odd ? 40 : 20);
});

Note that this refers to the current HTML or SVG element (or the ith element in the selection). If you wish to modify it using D3 you can select it using select(this).

.call()

The .call method allows a function to be called into which the selection itself is passed as the first argument.

.call is useful where you want a reusable function that operates on a selection.

For example, colorAll takes a selection and sets the fill of the selection's elements to orange:

function colorAll(selection) {
selection
.style('fill', 'orange');
}

selectAll('circle')
.call(colorAll);

Filtering and sorting selections

You can filter a selection using D3's .filter method. The first argument is a function which returns true if the element should be included. The filtered selection is returned by the filter method so you can continue chaining selection methods.

Thie example filters for even-numbered elements and colours them orange:

selectAll('circle')
.filter(function(d, i) {
return i % 2 === 0;
})
.style('fill', 'orange');

Sorting only really makes sense if data has been joined to the selection so knowledge of data joins is helpful.

You can sort elements in a selection by calling .sort and passing in a comparator function. The comparator function has two arguments, usually a and b, which represent the datums on the two elements being compared. If the comparator function returns a negative number, a will be placed before b and if positive, a will be placed after b.

Thus if you have the following data joined to a selection:

[
{
"name": "Andy",
"score": 37
},
{
"name": "Beth",
"score": 39
},
{
"name": "Craig",
"score": 31
},
{
"name": "Diane",
"score": 35
},
{
"name": "Evelyn",
"score": 38
}
]

you can sort by score using:

  selectAll('.person')
.sort(function(a, b) {
return b.score - a.score;
});
BOOKS & COURSES
D3 Start to Finish book cover

Data Dashboards with JavaScript teaches you how to build data dashboards using React, Chart.js and Leaflet.

Find out more

"One of the best D3 books I've read. The contents are very clear, it is easy to follow and the concepts are very solid."

Javier García Fernández

Learn how to make a custom data visualisation using D3.js.

Find out more
D3 Start to Finish book cover

Visualising Data with JavaScript teaches you how to build charts and data stories using Chart.js, Leaflet, D3 and React.

Find out more

Learn the fundamentals of HTML, SVG, CSS and JavaScript for building data visualisations on the web.

Find out more