0

I'm doing a react component which is an SVG animation. The react component's code is something like this:

const Loading = ({ className, ...props }) => {
  return (
    <svg
      aria-label="animated block"
      width="32"
      height={"32"}
      className={className}
      {...props}
    >
      <rect x="1" y="0" width="19" height="8" opacity="0.4" rx="5">
        <animate
          id="anim1"
          attributeName="width"
          from="19"
          to="8"
          begin="0s;anim2.end"
          dur="0.3s"
        />
        <animate
          id="anim2"
          attributeName="width"
          from="8"
          to="19"
          begin="anim1.end"
          dur="0.3s"
        />
      </rect>
    </svg>
  )
}

When showing a page with more than one of these, the accessibility linters show me the error "id attribute value must be unique".

Is there any way to avoid this error?

I've tried using aria-hidden both in the svg element and in each animate element, but with no success.

flapas
  • 583
  • 1
  • 11
  • 25
  • 1
    Does this answer your question? [React: unique ID generation](https://stackoverflow.com/questions/48006903/react-unique-id-generation) – Sean Dec 27 '21 at 14:15
  • 1
    Note, this isn't just an accessibility problem. It's invalid HTML to have duplicate IDs in a single document. – Sean Dec 27 '21 at 14:16
  • Was trying to avoid that, but I am getting to the conclusion that there's no escape from generating ids or passing a prop – flapas Dec 27 '21 at 16:31

2 Answers2

1

Maybe you can pass a unique id in props

Example:

const Loading = ({ className, id, ...props }) => {
  return (
    <svg
      aria-label="animated block"
      width="32"
      height={"32"}
      className={className}
      {...props}
    >
      <rect x="1" y="0" width="19" height="8" opacity="0.4" rx="5">
        <animate
          id={`${id}-anim1`}
          attributeName="width"
          from="19"
          to="8"
          begin="0s;anim2.end"
          dur="0.3s"
        />
        <animate
          id={`${id}-anim2`}
          attributeName="width"
          from="8"
          to="19"
          begin="anim1.end"
          dur="0.3s"
        />
      </rect>
    </svg>
  )
}
Max G.
  • 733
  • 3
  • 10
  • That would indeed get rid of the error, but it's just not a very attractive nor scalable solution for my case, where this component could be used many times in the same page. Was hoping for some aria attributes which would simply make the linters ignore the issue. However, as @sean said in the comments, this is also an HTML issue. I guess I'll have to implement something like you suggested – flapas Dec 27 '21 at 16:30
1

It seems like the only reason you currently need IDs on those <animate> elements is because you have two separate animations that each start when the other ends:

<svg width="32" height="32" viewBox="0 0 32 32">
  <rect x="1" y="0" width="19" height="8" opacity="0.4" rx="5">
    <animate id="anim1" attributeName="width" from="19" to="8" begin="0s;anim2.end" dur="0.3s" />
    <animate id="anim2" attributeName="width" from="8" to="19" begin="anim1.end" dur="0.3s" />
  </rect>
</svg>

It would be better to write this as a single <animation> element, using the values attribute and repeatCount instead of to and from attributes on two animation elements that reference each other. The exact same animation can be achieved like this:

<svg width="32" height="32" viewBox="0 0 32 32">
  <rect x="1" y="0" width="19" height="8" opacity="0.4" rx="5">
    <animate attributeName="width" values="19;8;19" to="8" dur="0.6s" repeatCount="indefinite" />
  </rect>
</svg>

This eliminates the need to reference one element from another, and therefore removes the need for IDs entirely.

Sean
  • 6,873
  • 4
  • 21
  • 46
  • This is great! It is the best solution for my case without a doubt. Thanks for pointing this out. Now that I think of it, in general, it should be the first thing to try. – flapas Dec 27 '21 at 16:44