0
votes

I have a svg react component with linearGradient that I render in my Header component and my main component. When I set display: none style to the Header component, I expect the svg in the Header component to be hidden and the svg in the main component to be visible. When I use svg without linearGradient, I get the expected behavior of svg hidden in Header and visible in main component. However, if the svg uses linearGradient, then setting display: none to the Header hides the svg in the Header and the main component.

To reproduce the issue, I have 2 react components PythonIcon (using linearGradient) and WebpackIcon (not using linearGradient). In my App.js, I render the Header and also render both PythonIcon and WebpackIcon in my main component:

import React from "react";
import Header from "./Header";
import PythonIcon from "./PythonIcon";
import WebpackIcon from "./WebpackIcon";

function App() {
  return (
    <div>
      <Header />
      <main style={{ marginTop: "1rem", border: "1px solid green" }}>
        <h1>
          <PythonIcon width="20" height="20" />
          Python
        </h1>
        <h1>
          <WebpackIcon width="20" height="20" />
          Webpack
        </h1>
      </main>
    </div>
  );
}

export default App;

In my Header component, I also render PythonIcon and WebpackIcon

import React from "react";
import PythonIcon from "./PythonIcon";
import WebpackIcon from "./WebpackIcon";

export default function Header() {
  return (
    <header style={{ border: "1px solid red", display: "block" }}>
      <h1>
        <PythonIcon width="20" height="20" />
        Python
      </h1>
      <h1>
        <WebpackIcon width="20" height="20" />
        Webpack
      </h1>
    </header>
  );
}

And the page looks like this:

a

But once I change display: block to display: none in the Header component, the page looks like this:

b

Notice that the webpack icon (which doesn't use linearGradient) is correctly showing in main component, but the python icon (which uses linearGradient) is not.

This was unexpected. Am I doing something wrong? Is there any way to hide the python icon in the header without having it hide the python icon in the main component? I am trying to create a responsive navbar using css media-query to show/hide navbar. Unfortunately, hiding the navbar w/ svg icons also hides the svg icon in my other components that I render.

I've provided a minimal reproduction at https://github.com/kimbaudi/react-svg-lineargradient-issue

1
I think I have an idea why I am getting this issue. It is probably because using linearGradient in svgs require id so rendering multiple svgs using linearGradient will render multiple elements with the same id. I'll need to see if passing unique id as prop to the svgs w/ linearGradient solves the issue.kimbaudi
Don¡t do display:none. Try width and height 0 for the svg element. You can add position:absolute and throw it out the window with leftenxaneta

1 Answers

0
votes

So I found a solution to this problem. The reason this is happening is because svgs using linearGradient or radialGradient contain ids and when you render multiple svgs in a page, it causes weird things to happen because the DOM expects there to be a unique id.

So my previous PythonIcon react svg component had hardcoded ids and looked like this:

import React from "react";

const PythonIcon = (props) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 64 64"
    width="64"
    height="64"
    {...props}
  >
    <linearGradient
      id="pythonLinearGradient1"
      x1="611.11"
      x2="720.13"
      y1="-280.51"
      y2="-374.3"
      gradientTransform="matrix(.32049 0 0 -.32362 -197.36 -88.951)"
      gradientUnits="userSpaceOnUse"
    >
      <stop stopColor="#5A9FD4" offset="0" />
      <stop stopColor="#306998" offset="1" />
    </linearGradient>
    <path
      fill="url(#pythonLinearGradient1)"
      strokeWidth=".56976"
      d="m31.344 0c-2.6209 0-5.1278 0.2279-7.2929 0.62674-6.4383 1.1395-7.6348 3.5325-7.6348 7.9197v5.8116h15.27v1.9372h-21.024c-4.4441 0-8.3185 2.6779-9.572 7.7488-1.4244 5.8116-1.4814 9.458 0 15.498 1.0825 4.5011 3.7034 7.7488 8.1476 7.7488h5.2418v-6.9511c0-5.0139 4.3872-9.515 9.572-9.515h15.27c4.2732 0 7.6348-3.4755 7.6348-7.7488v-14.529c0-4.1593-3.4755-7.236-7.6348-7.9197-2.6209-0.45581-5.3558-0.62674-7.9767-0.62674zm-8.2615 4.672c1.5953 0 2.8488 1.3104 2.8488 2.9058 0 1.5953-1.3104 2.9058-2.8488 2.9058-1.5953 0-2.8488-1.3104-2.8488-2.9058 0-1.5953 1.2535-2.9058 2.8488-2.9058z"
    />
    <linearGradient
      id="pythonLinearGradient2"
      x1="762.27"
      x2="723.34"
      y1="-431.07"
      y2="-375.99"
      gradientTransform="matrix(.32049 0 0 -.32362 -197.36 -88.951)"
      gradientUnits="userSpaceOnUse"
    >
      <stop stopColor="#FFD43B" offset="0" />
      <stop stopColor="#FFE873" offset="1" />
    </linearGradient>
    <path
      fill="url(#pythonLinearGradient2)"
      strokeWidth=".56976"
      d="m48.836 16.352v6.7802c0 5.2418-4.4441 9.6859-9.572 9.6859h-15.213c-4.1593 0-7.6348 3.5895-7.6348 7.7488v14.529c0 4.1593 3.5895 6.5523 7.6348 7.7488 4.843 1.4244 9.458 1.6523 15.27 0 3.8744-1.1395 7.6348-3.3616 7.6348-7.7488v-5.8116h-15.27v-1.9372h22.904c4.4441 0 6.0964-3.0767 7.6348-7.7488 1.5953-4.786 1.5384-9.4011 0-15.498-1.0825-4.4441-3.1907-7.7488-7.6348-7.7488zm-8.5464 36.807c1.5953 0 2.8488 1.3104 2.8488 2.9058 0 1.5953-1.3104 2.9058-2.8488 2.9058-1.5953 0-2.8488-1.3105-2.8488-2.9058-0.05698-1.5953 1.2535-2.9058 2.8488-2.9058z"
    />
  </svg>
);

export default PythonIcon;

Now I append a random string (I'm just using Math.random() for demo purpose) to the ids and I no longer have the issue of Python icon disappearing on main body when I hide Header. Here is the updated PythonIcon component:

import React from "react";

const PythonIcon = (props) => {
  const rand1 = Math.random()
  const rand2 = Math.random()
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 64 64"
      width="64"
      height="64"
      {...props}
    >
      <linearGradient
        id={`pythonLinearGradient1-${rand1}`}
        x1="611.11"
        x2="720.13"
        y1="-280.51"
        y2="-374.3"
        gradientTransform="matrix(.32049 0 0 -.32362 -197.36 -88.951)"
        gradientUnits="userSpaceOnUse"
      >
        <stop stopColor="#5A9FD4" offset="0" />
        <stop stopColor="#306998" offset="1" />
      </linearGradient>
      <path
        fill={`url(#pythonLinearGradient1-${rand1})`}
        strokeWidth=".56976"
        d="m31.344 0c-2.6209 0-5.1278 0.2279-7.2929 0.62674-6.4383 1.1395-7.6348 3.5325-7.6348 7.9197v5.8116h15.27v1.9372h-21.024c-4.4441 0-8.3185 2.6779-9.572 7.7488-1.4244 5.8116-1.4814 9.458 0 15.498 1.0825 4.5011 3.7034 7.7488 8.1476 7.7488h5.2418v-6.9511c0-5.0139 4.3872-9.515 9.572-9.515h15.27c4.2732 0 7.6348-3.4755 7.6348-7.7488v-14.529c0-4.1593-3.4755-7.236-7.6348-7.9197-2.6209-0.45581-5.3558-0.62674-7.9767-0.62674zm-8.2615 4.672c1.5953 0 2.8488 1.3104 2.8488 2.9058 0 1.5953-1.3104 2.9058-2.8488 2.9058-1.5953 0-2.8488-1.3104-2.8488-2.9058 0-1.5953 1.2535-2.9058 2.8488-2.9058z"
      />
      <linearGradient
        id={`pythonLinearGradient2-${rand2}`}
        x1="762.27"
        x2="723.34"
        y1="-431.07"
        y2="-375.99"
        gradientTransform="matrix(.32049 0 0 -.32362 -197.36 -88.951)"
        gradientUnits="userSpaceOnUse"
      >
        <stop stopColor="#FFD43B" offset="0" />
        <stop stopColor="#FFE873" offset="1" />
      </linearGradient>
      <path
        fill={`url(#pythonLinearGradient2-${rand2})`}
        strokeWidth=".56976"
        d="m48.836 16.352v6.7802c0 5.2418-4.4441 9.6859-9.572 9.6859h-15.213c-4.1593 0-7.6348 3.5895-7.6348 7.7488v14.529c0 4.1593 3.5895 6.5523 7.6348 7.7488 4.843 1.4244 9.458 1.6523 15.27 0 3.8744-1.1395 7.6348-3.3616 7.6348-7.7488v-5.8116h-15.27v-1.9372h22.904c4.4441 0 6.0964-3.0767 7.6348-7.7488 1.5953-4.786 1.5384-9.4011 0-15.498-1.0825-4.4441-3.1907-7.7488-7.6348-7.7488zm-8.5464 36.807c1.5953 0 2.8488 1.3104 2.8488 2.9058 0 1.5953-1.3104 2.9058-2.8488 2.9058-1.5953 0-2.8488-1.3105-2.8488-2.9058-0.05698-1.5953 1.2535-2.9058 2.8488-2.9058z"
      />
    </svg>
  );
};

export default PythonIcon;

and here is the screenshot showing the expected behavior of the Python icon not being hidden when the Header is hidden using display: none

d