vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.04k stars 26.71k forks source link

Title elements in `head.tsx` incompatible with multiple children such as variables from i18n #45389

Open ChristianIvicevic opened 1 year ago

ChristianIvicevic commented 1 year ago

Verify canary release

Provide environment information

    Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.2.0: Fri Nov 11 02:04:44 PST 2022; root:xnu-8792.61.2~4/RELEASE_ARM64_T8103
    Binaries:
      Node: 18.13.0
      npm: 8.19.3
      Yarn: 1.22.19
      pnpm: 7.9.0
    Relevant packages:
      next: 13.1.6
      eslint-config-next: 13.1.6
      react: 18.2.0
      react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true), Head component/file (next/head / head.js)

Link to the code that reproduces this issue

https://github.com/ChristianIvicevic/next-appdir-title-children-repro

To Reproduce

  1. Head into /src/app/head.tsx
  2. Append a custom variable to the title such as this

    export default function Head() {
    const titleFromDb = 'Foo'; // Could be from DB or i18n or whatnot
    
    return (
    <>
      <title>{titleFromDb} - Create Next App</title>
      <meta content="width=device-width, initial-scale=1" name="viewport" />
      <meta name="description" content="Generated by create next app" />
      <link rel="icon" href="/favicon.ico" />
    </>
    )
    }

Describe the Bug

Title is not rendered as expected and falls back to next parent title. Throws the following "warning":

Warning: A title element received an array with more than 1 element as children. In browsers title Elements can only have Text Nodes as children. If the children being rendered output more than a single text node in aggregate the browser will display markup and comments as text in the title and hydration will likely fail and fall back to client rendering
    at title
    at ReactDevOverlay (webpack-internal:///(sc_client)/./node_modules/next/dist/client/components/react-dev-overlay/internal/ReactDevOverlay.js:58:9)
    at HotReload (webpack-internal:///(sc_client)/./node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:18:22)
    at Router (webpack-internal:///(sc_client)/./node_modules/next/dist/client/components/app-router.js:96:23)
    at ErrorBoundaryHandler (webpack-internal:///(sc_client)/./node_modules/next/dist/client/components/error-boundary.js:61:9)
    at ErrorBoundary (webpack-internal:///(sc_client)/./node_modules/next/dist/client/components/error-boundary.js:73:26)
    at AppRouter (webpack-internal:///(sc_client)/./node_modules/next/dist/client/components/app-router.js:19:13)
    at Lazy
    at Lazy
    at ServerComponentWrapper (/Users/near/Code/Personal/next13-boilerplate/node_modules/next/dist/server/app-render.js:389:28)
    at ServerComponentWrapper (/Users/near/Code/Personal/next13-boilerplate/node_modules/next/dist/server/app-render.js:389:28)
    at InsertedHTML (/Users/near/Code/Personal/next13-boilerplate/node_modules/next/dist/server/app-render.js:1073:33)

Expected Behavior

Title renders as Foo - Create Next App.

A possible workaround is to interpolate using something like this:

<title>{`${titleFromDb} - Create Next App`}</title>

This is however inconvenient for adding HTML entities such as &mdash; instead of the hyphen which would work otherwise when just writing this for example:

<title>Foo &mdash; Create Next App</title>

Which browser are you using? (if relevant)

n/a

How are you deploying your application? (if relevant)

n/a

finkrer commented 1 year ago

This isn't related to the app directory, it's the same with next/head. In fact, the error message is displayed by React, not Next. The issue likely surfaced after upgrading the React version to use the app directory.