Repository: garmeeh/next-seo (js)

Issue:
keyOverride prop rendering as an attribute on meta tags
**Describe the bug**
There's a `keyOverride` property you can pass to meta tags to distinguish multiple tags with the same name (see #638). The tag object is spread as props over the `meta` element:

https://github.com/garmeeh/next-seo/blob/815e6361e900ad7d6c219a552f1456076d8bec13/src/meta/buildTags.tsx#L645-L650

This results in a rendered attribute of `keyoverride` on the resulting `meta` tag, which is invalid.

**Reproduction**
Todo, sorry not had chance yet

**Expected behavior**
Expected result is the provided `keyOverride` prop is used for the internal `key` prop but not rendered as an attribute.

**Additional context**
#638 is related and how I discovered it. #666 is where the functionality was added.

It's worth saying the same issue doesn't happen for `link` tags because they use a combination of `rel` and `href` for the generated `key` prop:

https://github.com/garmeeh/next-seo/blob/815e6361e900ad7d6c219a552f1456076d8bec13/src/meta/buildTags.tsx#L658

Pull request description:
Remove keyoverride attribute from additional meta tags
## Description of Change(s):

Fixes #1079.

- Stops the `keyOverride` prop for `additionalMetaTags` being rendered as a `keyoverride` attribute.
- Improves the readme around the `keyOverride` prop



Patch:
diff --git a/APP_DIRECTORY.md b/APP_DIRECTORY.md
index b414b97..0cb9236 100644
--- a/APP_DIRECTORY.md
+++ b/APP_DIRECTORY.md
@@ -1,5 +1,8 @@
 # Next.js App Directory Support
 
+> ⚠ Warning: Currently, the Head export does not re-render on client-side transitions, only on initial render. Read more [here](https://beta.nextjs.org/docs/api-reference/file-conventions/head#:~:text=Warning%3A%20Currently%2C%20the%20Head%20export%20does%20not%20re%2Drender%20on%20client%2Dside%20transitions%2C%20only%20on%20initial%20render.
+)
+
 With the introduction of the app directory there have been a lot of changes to how the `<head>` is now handled internally by Next.js.
 As a result of this, how we use `NextSeo` in our apps will also change.
 
@@ -445,4 +448,4 @@ Hopefully this gets you up and running with the new app directory.
 
 If you have any feedback be sure to let me know over [here](https://github.com/garmeeh/next-seo/discussions/1073)
 
-The examples above can be found the example app in this repo [here](https://github.com/garmeeh/next-seo/e2eWithApp)
+The examples above can be found the example app in this repo [here](https://github.com/garmeeh/next-seo/tree/master/e2eWithApp)
diff --git a/README.md b/README.md
index 0051a87..8c519ec 100644
--- a/README.md
+++ b/README.md
@@ -574,17 +574,16 @@ additionalMetaTags={[{
 }]}
 ```
 
-One thing to note on this is that it currently only supports unique tags.
-This means it will only render one tag per unique `name` / `property` / `httpEquiv`. The last one defined will be rendered.
+One thing to note on this is that it currently only supports unique tags, unless you use the `keyOverride` prop to provide a unique [key](https://reactjs.org/docs/lists-and-keys.html#keys) to each additional meta tag.
 
-Example:
+The default behaviour (without a `keyOverride` prop) is to render one tag per unique `name` / `property` / `httpEquiv`. The last one defined will be rendered.
 
-If you pass:
+For example if you pass 2 tags with the same `property`:
 
 ```js
 additionalMetaTags={[{
   property: 'dc:creator',
-  content: 'John Doe'
+  content: 'Joe Bloggs'
 }, {
   property: 'dc:creator',
   content: 'Jane Doe'
@@ -594,7 +593,28 @@ additionalMetaTags={[{
 it will result in this being rendered:
 
 ```html
-<meta property="dc:creator" content="Jane Doe" />,
+<meta property="dc:creator" content="Jane Doe" />
+```
+
+Providing an additional `keyOverride` property like this:
+
+```js
+additionalMetaTags={[{
+  property: 'dc:creator',
+  content: 'Joe Bloggs',
+  keyOverride: 'creator1',
+}, {
+  property: 'dc:creator',
+  content: 'Jane Doe',
+  keyOverride: 'creator2',
+}]}
+```
+
+results in the correct HTML being rendered:
+
+```html
+<meta property="dc:creator" content="Joe Bloggs" />
+<meta property="dc:creator" content="Jane Doe" />
 ```
 
 #### Additional Link Tags
diff --git a/src/meta/buildTags.tsx b/src/meta/buildTags.tsx
index 4998684..0560ea1 100644
--- a/src/meta/buildTags.tsx
+++ b/src/meta/buildTags.tsx
@@ -188,13 +188,9 @@ const buildTags = (config: BuildTagsParams) => {
     );
   }
 
-  if(config.themeColor){
+  if (config.themeColor) {
     tagsToRender.push(
-      <meta
-        key="theme-color"
-        name="theme-color"
-        content={config.themeColor}
-      />
+      <meta key="theme-color" name="theme-color" content={config.themeColor} />,
     );
   }
 
@@ -640,11 +636,11 @@ const buildTags = (config: BuildTagsParams) => {
   }
 
   if (config.additionalMetaTags && config.additionalMetaTags.length > 0) {
-    config.additionalMetaTags.forEach(tag => {
+    config.additionalMetaTags.forEach(({ keyOverride, ...tag }) => {
       tagsToRender.push(
         <meta
           key={`meta:${
-            tag.keyOverride ?? tag.name ?? tag.property ?? tag.httpEquiv
+            keyOverride ?? tag.name ?? tag.property ?? tag.httpEquiv
           }`}
           {...tag}
         />,


Test patch:
diff --git a/src/meta/__tests__/buildTags.spec.tsx b/src/meta/__tests__/buildTags.spec.tsx
index 9ce9106..4922896 100644
--- a/src/meta/__tests__/buildTags.spec.tsx
+++ b/src/meta/__tests__/buildTags.spec.tsx
@@ -872,6 +872,28 @@ it('additional meta tags are set', () => {
   expect(Array.from(httpEquivTag).length).toBe(1);
 });
 
+it('uses key override to render multiple additional meta tags with the same key', () => {
+  const overrideProps: BuildTagsParams = {
+    ...SEO,
+    additionalMetaTags: [
+      { property: 'foo', content: 'Foo 1', keyOverride: 'foo1' },
+      { property: 'foo', content: 'Foo 2', keyOverride: 'foo2' },
+      { name: 'bar', content: 'Bar 1', keyOverride: 'bar1' },
+      { name: 'bar', content: 'Bar 2', keyOverride: 'bar2' },
+    ],
+  };
+  const tags = buildTags(overrideProps);
+  const { container } = render(<>{React.Children.toArray(tags)}</>);
+
+  const propertyTags = container.querySelectorAll('meta[property="foo"]');
+  expect(Array.from(propertyTags).length).toBe(2);
+  expect(propertyTags[0]).not.toHaveAttribute('keyoverride');
+
+  const nameTags = container.querySelectorAll('meta[name="bar"]');
+  expect(Array.from(nameTags).length).toBe(2);
+  expect(nameTags[0]).not.toHaveAttribute('keyoverride');
+});
+
 it('correctly sets noindex default', () => {
   const overrideProps: BuildTagsParams = {
     ...SEO,