# Setting CSS Custom Properties with d3 on each element

**URL:** https://talk.observablehq.com/t/setting-css-custom-properties-with-d3-on-each-element/6534
**Category:** Help
**Created:** [May 8, 2022, 10:12pm UTC](https://talk.observablehq.com/t/setting-css-custom-properties-with-d3-on-each-element/6534 "2022-05-08T22:12:38Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![smpa01](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/smpa01/32/5352_2.png) [@smpa01](https://talk.observablehq.com/u/smpa01)
#### Post date: [May 8, 2022, 10:12pm UTC](https://talk.observablehq.com/t/setting-css-custom-properties-with-d3-on-each-element/6534/1 "2022-05-08T22:12:38Z")

</div>

I am working with a svg element & the initial markup is following

```auto
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
	
<body>
<svg xmlns="http://www.w3.org/2000/svg" height="400" width="450">
  <path class="line1" d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none" />
  <path class="line2" d="M 250 50 l 150 300" stroke="blue" stroke-width="3" fill="none" />
  <path class="line3" d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
  <path class="line4" d="M 100 350 q 150 -300 300 0" stroke="magenta" stroke-width="5" fill="none" />

</svg>
</body>
</html>

```

I want to call [getTotalLength](https://developer.mozilla.org/en-US/docs/Web/API/SVGGeometryElement/getTotalLength) on each `path` and set that as CSS custom properties for each `path`.

By using vanilla, I can do this

```auto
document.querySelectorAll("[class^='line']")
    .forEach(
        (a, i) => {
            a.style.setProperty('--pathLength', a.getTotalLength());
        }
    );

```

which gives me

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/8/819398d1042b0d99d09ab846aac98f64052e5ac9.png)

I was wondering, how can I replicate this in `d3`. So far, I tried this which is doing the job but I am doing the same selection twice.

```auto
d3.selectAll("[class^='line']")
    .style('--pathLength', (d, i) => {
        const dataset = d3.selectAll("[class^='line']");
        return `${dataset['_groups'][0][i].getTotalLength()}`
    });

```

Is there a better way to achieve this?

The full code is following

```auto
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>
	
<body>

<svg xmlns="http://www.w3.org/2000/svg" height="400" width="450">
  <path class="line1" d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none" />
  <path class="line2" d="M 250 50 l 150 300" stroke="blue" stroke-width="3" fill="none" />
  <path class="line3" d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
  <path class="line4" d="M 100 350 q 150 -300 300 0" stroke="magenta" stroke-width="5" fill="none" />

</svg>
<script type="text/javascript">
<!--vanilla-->
document.querySelectorAll("[class^='line']")
    .forEach(
        (a, i) => {
            a.style.setProperty('--pathLengthVanilla', a.getTotalLength());
        }
    );
<!--d3-->	
d3.selectAll("[class^='line']")
    .style('--pathLengthD3', (d, i) => {
        const dataset = d3.selectAll("[class^='line']");
        return `${dataset['_groups'][0][i].getTotalLength()}`
    });	
</script>
</body>

</html>

```

---

<div class="post-metadata">

### Author: ![tophtucker](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/tophtucker/32/4781_2.png) [@tophtucker](https://talk.observablehq.com/u/tophtucker)
#### Post date: [May 9, 2022, 3:27am UTC](https://talk.observablehq.com/t/setting-css-custom-properties-with-d3-on-each-element/6534/2 "2022-05-09T03:27:24Z")

</div>

In D3, the `selection.style` method takes a property name (`"--pathLength"`) and a callback, which is invoked with the element as the value of `this`, so you can return `this.getTotalLength()`:

```nohighlight
d3.selectAll("[class^='line']")
  .style("--pathLength", function (d, i) {
    return this.getTotalLength();
  });

```

Note that, for the value of `this` to be the element, you can’t use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), which don’t get their own `this`. That is, you can’t write `(d, i) => { ... }`, like you did in your example; you have to write `function(d, i) { ... }`.

Here’s an example:

> **[Setting path length as CSS property variable with D3](https://observablehq.com/@tophtucker/setting-path-length-as-css-property-variable-with-d3)**
>
> Smpa01 asks in the forum: I want to call getTotalLength on each path and set that as CSS custom properties for each path. By using vanilla, I can do this: I was wondering, how can I replicate this in d3. In D3, you can do something very similar. The...

---

<div class="post-metadata">

### Author: ![smpa01](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/smpa01/32/5352_2.png) [@smpa01](https://talk.observablehq.com/u/smpa01)
#### Post date: [May 9, 2022, 2:54pm UTC](https://talk.observablehq.com/t/setting-css-custom-properties-with-d3-on-each-element/6534/3 "2022-05-09T14:54:26Z")

</div>

@tophtucker many thanks for this. However, I have a follow-up question. I am new to d3 and currently experimenting with d3 API.

I have conducted the following experiment to get more clarification on use of `d` and `this`

```auto
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script>

<body>

    <svg xmlns="http://www.w3.org/2000/svg" height="400" width="450">
  <path class="line1" d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none" />
  <path class="line2" d="M 250 50 l 150 300" stroke="blue" stroke-width="3" fill="none" />
  <path class="line3" d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
  <path class="line4" d="M 100 350 q 150 -300 300 0" stroke="magenta" stroke-width="5" fill="none" />

</svg>
    <script type="text/javascript">
        /*vanilla*/
        document.querySelectorAll("[class^='line']")
            .forEach(
                (a, i) => {
                    a.style.setProperty('--pathLengthVanilla', a.getTotalLength());
                }
            );
        /*d3*/
        d3.selectAll("[class^='line']")
            .style('--pathLengthD3', (d, i) => {
                const dataset = d3.selectAll("[class^='line']");
                return `${dataset['_groups'][0][i].getTotalLength()}`
            });

        /*perform dynamic transform on the existing element by selecting first*/
        d3.selectAll("[class^='line']").attr('transform', function(d, i) {
            const attributeX = parseFloat(this.getAttribute('d').match(/(?<=M )\d+/gm)) / 10;
            return `translate(${attributeX})`
        })

        /*create data driven circle and dynamic transform on the new element based on the dataset*/
        d3.select('svg')
            .selectAll('circle')
            .data(d3.selectAll("[class^='line']"))
            .enter()
            .append('circle')
            .attr('cx', '0')
            .attr('cy', (d, i) => {
                return '5'
            })
            .attr('r', '5')
            .attr('transform', (d, i) => {
                    const attributeX = parseFloat(d.getAttribute('d').match(/(?<=M )\d+/gm)) / 10
                    return `translate(${attributeX})`
                }

            )
    </script>
</body>

</html>

```

As you can notice, line **38** requires _ **`this`** _ and line **55** requires _ **`d`** _

 ![image](https://canada1.discourse-cdn.com/flex030/uploads/observablehq/original/2X/d/d5d742e26a86756e6369849829f770a29c17de6d.png)

Is it kindly possible for you to shed some light on this as to when to use _ **`this`** _ and when to use  
_ **`d`** _.  
From this example, it is explanatory that `this` is required for modifying existing elements and `d` is used for the new data-driven element.

Since I am new to d3, I am not sure if this is the correct inference ? I would love to hear some explanation from you.

---

<div class="post-metadata">

### Author: ![mcmcclur](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mcmcclur/32/2364_2.png) [@mcmcclur](https://talk.observablehq.com/u/mcmcclur)
#### Post date: [May 9, 2022, 3:20pm UTC](https://talk.observablehq.com/t/setting-css-custom-properties-with-d3-on-each-element/6534/4 "2022-05-09T15:20:40Z")

</div>

> [@smpa01](#):
>
> Is it kindly possible for you to shed some light on this as to when to use _ **`this`** _ and when to use  
> _ **`d`** _.

I can never keep this straight myself so I often myself using a `console.log` to examine those things. For example, you might type:

```
.attr('some_attribute', function(a,b) {
  console.log([a,b,this])
  ...
}

```

That way, you can simply examine the contents of those variables and decide how to act accordingly.
