0

I have a data object that contains data to find a specific element that exist within a DOM Tree and after I find that element I want to change it css by adding inline css.

    {
      outerHtml: '<a class="btn btn-pill">\n                        <svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path>',
      selector: ".col-auto.ml-auto.d-print-none>.d-flex>.btn.btn-pill",
      style: `background-color: #206bc4; color: white; svg { color: white }`,
    }

I'm utilizing this data and injecting the style data in to the element once I find it. As you can see in my outerHTML, the parent prop also has a child and in my style I have the css to change the svg color as well. But when using my code below. It only changes the style of the a tag as opposed to the svg as well.

Note: the outerHTML & selector are just for finding the correct element to change. Sort of like unique identifiers

All I'm doing in the below code is using my selectors to find the correct element and then add the CSS to the final node.

export function findAndInject(remove) {
  const data = getData();
  let selector = data.selector.split(',');
  let select;
  for (const prop in selector) {
    if (prop == 0) {
      select = document.querySelector(selector[prop]);
    } else {
      select = select.querySelector(selector[prop]);
    }
  }
  if (remove) {
    select.style.cssText = null;
  } else {
    select.style.cssText = data.style;
  }
}

I know the issue is probably that I'm doing style.cssText but is there any other way I can add an inline style that can also be added to the child without creating a stylesheet or using style tags?

Before Injection:
Before Injection

After Injection:
After Injection

The Plus icon should be white.

Nikster
  • 1
  • 1

2 Answers2

0

The short answer is: No, it is not possible to add inline styles that can also be applied to the child. For a good explanation as to why "why", you can refer to this post (https://stackoverflow.com/a/5293299/3180489) which succinctly explains (with references):

Neither selectors (including pseudo-elements), nor at-rules, nor any other CSS construct are allowed.

Think of inline styles as the styles applied to some anonymous super-specific ID selector: those styles only apply to that one very element with the style attribute. (They take precedence over an ID selector in a stylesheet too, if that element has that ID.) Technically it doesn't work like that; this is just to help you understand why the attribute doesn't support pseudo-class or pseudo-element styles (it has more to do with how pseudo-classes and pseudo-elements provide abstractions of the document tree that can't be expressed in the document language).

With that being said, for this particular case you may be able to modify your SVG icons to "inherit" the color from the parent element, if you choose to go that route.

Steve
  • 11,596
  • 7
  • 39
  • 53
0

I guess the problem is your svg code – at least your example snippet won't work.

Here is a working example:

.icon {
  display: inline-block;
  height: 1em;
  font-size: 1em;
  position: relative;
  bottom: -0.1em;
}

.btn {
  padding: 0.3em;
}
<p>
  <a class="btn btn-pill" style="background-color: #206bc4; color: white;">
    <svg class="icon icon-plus" id="icon-plus" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
      <line x1="12" y1="5" x2="12" y2="19" class="icon-inner-stroke"></line>
      <line x1="5" y1="12" x2="19" y2="12" class="icon-inner-stroke"></line>
    </svg> New Campaign
  </a>
</p>
<p>
  <a class="btn btn-pill" style="background-color: #206bc4; color: white;">
    <svg class="icon icon-square-plus" viewBox="0 0 448 512">
      <path fill="currentColor" d="M319.1 232h-72V160c0-13.25-10.74-24-23.1-24S199.1 146.7 199.1 160v72H127.1C114.7 232 103.1 242.7 103.1 256S114.7 280 127.1 280h71.1V352c0 13.25 10.75 24 24 24s23.1-10.75 23.1-24V280h72c13.25 0 23.1-10.75 23.1-24S333.3 232 319.1 232zM384 32H64C28.65 32 0 60.65 0 96v320c0 35.35 28.65 64 64 64h320c35.35 0 64-28.65 64-64V96C448 60.65 419.3 32 384 32zM400 416c0 8.822-7.178 16-16 16H64c-8.822 0-16-7.178-16-16V96c0-8.822 7.178-16 16-16h320c8.822 0 16 7.178 16 16V416z"></path>
    </svg> New Campaign
  </a>
</p>

In your example the <path> element had both stroke and fill attributes explicitly set to none.
Therefore the currentColor fill rule was omitted.

Another approach could be the use of a custom property/css variable:

  <a class="btn btn-pill" style="background-color: #eee; --iconColor: green;">
    <svg class="icon icon-plus" id="icon-plus" width="16" height="16" viewBox="0 0 24 24" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" style="stroke:var(--iconColor)">
      <line x1="12" y1="5" x2="12" y2="19" class="icon-inner-stroke"></line>
      <line x1="5" y1="12" x2="19" y2="12" class="icon-inner-stroke"></line>
    </svg> New Campaign
  </a>
herrstrietzel
  • 11,541
  • 2
  • 12
  • 34