Accepted answer

You can modify Mike Bostock's "Wrapping Long Labels" example to add <tspan> elements to your <text> nodes. There are two major changes required to add wrapped text to your nodes. I didn't delve into having the text update its position during transitions, but it shouldn't be too hard to add.

The first is to add a function wrap, based off of the function in the above example. wrap will take care of adding <tspan> elements to make your text fit within a certain width:

function wrap(text, width) {
    text.each(function () {
        var text =,
            words = text.text().split(/\s+/).reverse(),
            line = [],
            lineNumber = 0,
            lineHeight = 1.1, // ems
            x = text.attr("x"),
            y = text.attr("y"),
            dy = 0, //parseFloat(text.attr("dy")),
            tspan = text.text(null)
                        .attr("x", x)
                        .attr("y", y)
                        .attr("dy", dy + "em");
        while (word = words.pop()) {
            tspan.text(line.join(" "));
            if (tspan.node().getComputedTextLength() > width) {
                tspan.text(line.join(" "));
                line = [word];
                tspan = text.append("tspan")
                            .attr("x", x)
                            .attr("y", y)
                            .attr("dy", ++lineNumber * lineHeight + dy + "em")

The second change is that instead of setting the text of each node, you need to call wrap for each node:

// Add entering nodes in the parent’s old position.
    .attr("class", "node")
    .attr("x", function (d) { return d.parent.px; })
    .attr("y", function (d) { return; })
    .text("Foo is not a long word")
    .call(wrap, 30); // wrap the text in <= 30 pixels


This is a way to text wrap using d3 plus. It's really easy for me and works in all browsers as of now



You can also use a plain HTML element inside your SVG by using a foreignObject.

For example, I used the following to append an HTML div to my svg object.

    .attr("width", blockWidth)
    .attr("height", blockHeight)
    .style("color", "#000")
    .style("text-align", "center")
    .style("width", "100%")
    .style("height", "100%")
    .style("padding", "5px")
    .style("font-size", `${fontSize}px`)
    .style("overflow-y", "auto")
    .html("The text to display")


<foreignObject width="200" height="50">
    <div style="color: rgb(0, 0, 0); text-align: center; width: 100%; height: 100%; padding: 5px; font-size: 12px; overflow-y: auto;">
        The text to display

You could also use a .attr('class', 'classname') instead of all the .style(...) calls and insert styles through a stylesheet if your styles are static.

Source (and more info/options) from this SO answer.


Another option, if you're willing to add another JS lib, is to use D3plus, a D3 addon. It has built-in text wrapping functionality. It even supports padding and resizing text to fill the available space.


I've used it. It sure beats calculating the wrapping yourself.

There's another d3 plugin available for text wrapping but I've never used it so I can't speak to it's usefulness.


If you're using React, a library you can use for this is @visx/text. It exposes a more powerful SVG text element that supports a width parameter.

import { Text } from '@visx/text';

const App = () => (
    <Text width={20}>Foo is not a long word</Text>