javascriptreactjsnext.js

Not able to change the title with metadata when using 'use client' in Next.js


I have a /demo route in my Next.js 13 application, and it is using the App Router. But I am unable to change the title of the page (the current title I am getting is localhost:3000/demo).

I have the following code.

/demo/page.js:

'use client'

 ....

export const metadata = {
  title: 'Demo - ModalJS',
};

export default Demo(){
 return ...
}

The 'use client' is creating the problem, because when I remove it Title changes, but the problem is that I cannot remove it because this component uses onClick which gives an error without ''use client`'

The code inside Demo is as follows:

export default function Demo() {
    

    const [title, setTitle] = useState("Title of your modal");
    const [desc, setDesc] = useState("You description goes here");
    const [theme, setTheme] = useState("light");

    const handleclick = ()=>{
        const modal = new ModalJS( ... stuff related to this library)
        
        modal.show()       //trigger this when you want to show modal
    }


    return <section id={styles.demosection}>
        <div className={styles.demotitle}>Demo</div>
        <div className={styles.form}>
            <label htmlFor="title" className={styles.label}>Title:</label> <br />
            <input type="text" name="title" id={styles.title} className={styles.input} value={title} onChange={(e)=>setTitle(e.target.value)}/>
<br /><br />
            <label htmlFor="desc" className={styles.label}>Description:</label> <br />
            <input type="text" name="desc" id={styles.desc} className={styles.input} value={desc} onChange={(e)=>setDesc(e.target.value)}/>
<br /><br />
            <label htmlFor="theme" className={styles.label}>Theme:</label> <br />
            <select type="select" name="theme" id={styles.theme} className={styles.input} onChange={(e)=>setTheme(e.target.value)}>
                <option value="light">light</option>
                <option value="dark">dark</option>
            </select>
<br /><br />

        </div>
        <div className={styles.showbtndiv}>
            <button className={styles.showbtn} onClick={()=>handleclick()}>Show Modal</button>
        </div>
    </section>
}

Solution

  • As you can read on the doc, you cannot have metadata in a client component. Here is the quote where they warn about that:

    Both static and dynamic metadata through generateMetadata are only supported in Server Components.

    So instead of having the whole page (or layout) as a client component, you could move the part where you need interactivity in a client file and import it into your server page, as they say:

    To improve the performance of your application, we recommend moving Client Components to the leaves of your component tree where possible.

    In your case, you could move the content of your current app/demo/page.js file inside a app/demo/demo.js file, for example, without the metadata, and import it:

    // app/demo/page.js
    
    import Demo from "./demo";
    
    export const metadata = {
      title: 'Demo - ModalJS',
    };
    
    export default Page(){
     return <div><Demo/></div>
    }
    
    // app/demo/demo.js
    
    'use client'
    
    // ....
    
    export default Demo(){
     return ...
    }