How can I get a div and all its children with their respective computedStyles?

Viewed 71

I would like to grab the HTML element and all it's computedStyles.

I managed to make it work when the HTML element has no children, but what if the HTML element has many children, how can I grab all the computedStyles of each child

here's what I have so far:

  • The user clicks on an html element, I grab the HTML element using event.target.cloneNode(true)
  • I then set an Id to the cloned element
  • I grab the computedStyle
  • Then I add the style to my cloned element
  private onClickHtmlCssGrabber = (event) => {
      // clone the html element
      let clickedHtmlElement = event.target.cloneNode(true)

      // set an id to the cloned element
      clickedHtmlElement.setAttribute('id', 'clonedElement')

      // get the computed style of the element
      let clikedHtmlElementStyle =  getComputedStyle(event.target).cssText

      // set the style on my newly cloned element
      clickedHtmlElement.style.cssText = clikedHtmlElementStyle
  }

So basically at this point I end up with something like:

<div id="clonedElement" style="... all the coputedStyle">Example text</div>

But my problem occurs when the HTML element that I want to extract has many children:

<div class="style1">
  <div class="style-child-1">
    <div class="style-child-2">
      example text child 2
    <div>
    <div class="style-child-3">
      example text child 3
    </div>
  <div>
</div>

So how can I extract the whole HTML element with its children and their styles ?

1 Answers

So I was curious about this myself and created a quick example to walk through an element. Should also work without any children in it, because the loop will simply not run.

// container where we want to put the clone
const targetContainer = document.querySelector('.target');

// your element that you want to clone
const root = document.querySelector('.style1');
const rootWalker = document.createTreeWalker(
    root,
    NodeFilter.SHOW_ELEMENT,
    { acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } }
);

// now clone the element and also creat a walker for it
const rootClone = root.cloneNode(true);
const cloneWalker = document.createTreeWalker(
    rootClone,
    NodeFilter.SHOW_ELEMENT,
    { acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; }}
);

// clone styles for the root element itself
rootClone.style.cssText = getComputedStyle(root).cssText
rootClone.className = '' // simply clearing it to see if styles are copied

// get the first child node, if there is no child, .nextNode() will return null
let nextRootNode = rootWalker.nextNode();
let nextCloneNode = cloneWalker.nextNode();

// now if we have a child node, the loop is running
while (nextRootNode !== null) {
  // get styles from original to clone
    nextCloneNode.style.cssText = getComputedStyle(nextRootNode).cssText;
  nextCloneNode.className = '' // again removing classes for demonstration
  
  // get next node, again if there are no more, null will be returned and loop will stop
  nextRootNode = rootWalker.nextNode();
  nextCloneNode = cloneWalker.nextNode();
}

// simply append the cloned node to your desired target
targetContainer.append(rootClone);
.style1 {
  background: yellow;
  padding: 10px;
  margin: 5px 0;
}

.style-child-1 {
  background: green;
  padding: 10px;
}

.style-child-2 {
  color: blue;
}

.style-child-3 {
  color: orange;
  text-transform: uppercase;
}
<div class="style1">
  <div class="style-child-1">
    <div class="style-child-2">
      example text child 2
    </div>
    <div class="style-child-3">
      example text child 3
    </div>
   </div>
</div>

<div class="target">

</div>

If you want you can grab this and fit it to your needs. Eg. creating a function and run it on click.

Related