282

I would like to set the document title (in the browser title bar) for my React application. I have tried using react-document-title (seems out of date) and setting document.title in the constructor and componentDidMount() - none of these solutions work.

theUtherSide
  • 3,338
  • 4
  • 36
  • 35
eli
  • 4,636
  • 7
  • 25
  • 29
  • I confirm, react-document-title works great with react 16.5 – DevTheJo Sep 23 '18 at 14:58
  • 2
    If you just want to change the title you can edit title in index.html file which contain inside the public folder – Ishan Fernando Apr 20 '22 at 09:43
  • 1
    @IshanFernando this is not a solution when you have multi-language support. We don't need a temporary page title from index.html flashing while a page is loading. – Dmitry Nov 22 '22 at 10:45

22 Answers22

265

For React 16.8+ you can use the Effect Hook in function components:

import React, { useEffect } from 'react';

function Example() {
  useEffect(() => {
    document.title = 'My Page Title';
  }, []);
}


To manage all valid head tags, including <title>, in declarative way, you can use React Helmet component:

import React from 'react';
import { Helmet } from 'react-helmet';

const TITLE = 'My Page Title';

class MyComponent extends React.PureComponent {
  render () {
    return (
      <>
        <Helmet>
          <title>{ TITLE }</title>
        </Helmet>
        ...
      </>
    )
  }
}
PSEUDO
  • 113
  • 4
  • 13
quotesBro
  • 6,030
  • 2
  • 31
  • 41
  • 3
    this will 'flash' the contents of the index.html in the first second, right? – nxmohamad Jun 19 '18 at 19:16
  • 6
    This should definitely be the top answer. It's an excellent declarative way to manage the title and other meta attributes – Ryall Nov 11 '18 at 13:05
  • 1
    Usage of helmet in React 16 has an issue https://github.com/nfl/react-helmet/issues/548 – pepeevich Apr 20 '21 at 08:28
  • 42
    Seems like overkill to set one single tag. – Reactgular Jun 22 '21 at 12:23
  • @nxmohamad Yes, the "flash" issue can be resolved by removing the title tag altogether from the index.html file. Only downside being you have to make sure to give a title on every page or else it defaults to the domain name. – Sandecoder Jul 29 '21 at 11:08
  • 6
    like @Reactgular said this is overkill. Generally it's not advisable to bring in dependencies to solve problems that can be easily solved with what's already available. Sure the API might be nicer than `document.title` but you've just introduced potentially more complexity for no palpable benefit by adding relying on a library for something like this. – ICW Jun 13 '22 at 18:05
  • @Reactgular agreed. I've updated the answer to point out that Helmet can be used to manage all head tags, not only title. And added an example of using Effect hook in React 16.8+ – quotesBro Jul 02 '22 at 09:18
  • You may not need useEffect() if you are using functional components. `document.title = props.title` can be set and updated with a props change. It can even be set inside of render. – Matt Jan 03 '23 at 19:16
  • 3
    Is there no way to modify the template for static code like this? Have we really come to a point where static content needs to be scripted? – Jeffrey Tillwick Jan 30 '23 at 22:12
189
import React from 'react'
import ReactDOM from 'react-dom'


class Doc extends React.Component{
  componentDidMount(){
    document.title = "dfsdfsdfsd"
  }

  render(){
    return(
      <b> test </b>
    )
  }
}

ReactDOM.render(
  <Doc />,
  document.getElementById('container')
);

This works for me.

Edit: If you're using webpack-dev-server set inline to true

theUtherSide
  • 3,338
  • 4
  • 36
  • 35
AlexVestin
  • 2,548
  • 2
  • 16
  • 20
158

For React 16.8, you can do this with a functional component using useEffect.

For Example:

useEffect(() => {
   document.title = "new title"
}, []);

Having the second argument as an array calls useEffect only once, making it similar to componentDidMount.

Jordan Daniels
  • 4,896
  • 1
  • 19
  • 29
  • How can this be tested with jest and enzyme? – nickstaroba Sep 29 '19 at 15:12
  • +1. Note that if the title is *computed* in some way -- which it probably is, otherwise you would just set it in `...` and not touch it in your React component -- then the second argument should probably be `["new title"]` rather than `[]`, so that React knows to re-execute this hook if/when the computed title changes. – ruakh Jun 05 '22 at 18:37
  • 1
    Until page loads it is React APP, then changes to "new title" very ugly. – nerkn Jul 08 '22 at 07:10
53

As others have mentioned, you can use document.title = 'My new title' and React Helmet to update the page title. Both of these solutions will still render the initial 'React App' title before scripts are loaded.

If you are using create-react-app the initial document title is set in the <title> tag /public/index.html file.

You can edit this directly or use a placeholder which will be filled from environmental variables:

/.env:

REACT_APP_SITE_TITLE='My Title!'
SOME_OTHER_VARS=...

If for some reason I wanted a different title in my development environment -

/.env.development:

REACT_APP_SITE_TITLE='**DEVELOPMENT** My TITLE! **DEVELOPMENT**'
SOME_OTHER_VARS=...

/public/index.html:

<!DOCTYPE html>
<html lang="en">
    <head>
         ...
         <title>%REACT_APP_SITE_TITLE%</title>
         ...
     </head>
     <body>
         ...
     </body>
</html>

This approach also means that I can read the site title environmental variable from my application using the global process.env object, which is nice:

console.log(process.env.REACT_APP_SITE_TITLE_URL);
// My Title!

See: Adding Custom Environment Variables

Gruffy
  • 1,431
  • 1
  • 14
  • 18
  • Make sure to put the .env files at the same level of your package.json file. :) – Ian Smith May 27 '20 at 16:05
  • I tried this but %REACT_APP_SITE_TITLE% is displayed as title. I have kept .env in same level as package.json and using react-scripts 3.4.1 – Yuvraj Patil Dec 17 '20 at 03:23
  • @YuvrajPatil This is only applied at build time. If you need to inject them at runtime, https://create-react-app.dev/docs/title-and-meta-tags#generating-dynamic-meta-tags-on-the-server – SajithK Feb 05 '21 at 03:16
  • 3
    I believe this is the most reasonable solution unless you want to change the title within a component – Nafiu Lawal Mar 01 '21 at 00:39
47

Since React 16.8. you can build a custom hook to do so (similar to the solution of @Shortchange):

export function useTitle(title) {
  useEffect(() => {
    const prevTitle = document.title
    document.title = title
    return () => {
      document.title = prevTitle
    }
  })
}

this can be used in any react component, e.g.:

const MyComponent = () => {
  useTitle("New Title")
  return (
    <div>
     ...
    </div>
  )
}

It will update the title as soon as the component mounts and reverts it to the previous title when it unmounts.

Master Bruce
  • 569
  • 5
  • 4
28
import React from 'react';

function useTitle(title: string): void => {
  React.useEffect(() => {
    const prevTitle = document.title;
    document.title = title;

    return () => {
      document.title = prevTitle;
    };
  }, []);
}

function MyComponent(): JSX.Element => {
  useTitle('Title while MyComponent is mounted');

  return <div>My Component</div>;
}

This is a pretty straight forward solution, useTitle sets the document title and when the component unmounts it's reset to whatever it was previously.

Shortchange
  • 406
  • 4
  • 5
  • 2
    This is the correct way to do it. But, it sure would be nice not to have to. The concept is reusable enough to just be on npm. – Eugene Kuzmenko Sep 29 '20 at 09:00
18

If you are wondering, you can set it directly inside the render function:

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
    render() {
        document.title = 'wow'
        return <p>Hello</p>
    }
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
)

For function component:

function App() {
    document.title = 'wow'
    return <p>Hello</p>
}

But, this is a bad practice because it will block the rendering (React prioritize the rendering first).

The good practice:

Class component:

class App extends React.Component {
    // you can also use componentDidUpdate() if the title is not static
    componentDidMount(){
        document.title = "good"
    }

    render() {
        return <p>Hello</p>
    }
}

Function component:

function App() {
    // for static title, pass an empty array as the second argument
    // for dynamic title, put the dynamic values inside the array
    // see: https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects
    useEffect(() => {
        document.title = 'good'
    }, []);

    return <p>Hello</p>
}
M Imam Pratama
  • 998
  • 11
  • 26
  • 8
    This is a typical error that appears in many react code bases: DON'T DO THAT ! Every render methods should be pure functions (no side effects), if you need to perform a side effect: useEffect for functional components, or component events in classes (more info: https://www.reddit.com/r/reactjs/comments/8avfej/what_does_side_effects_mean_in_react/dx1xo1l) – Elias Platek Jun 26 '20 at 15:43
  • +1 to Elias' comment. Even if you have the right way listed, this answer might cause people to put it in the `render` func. – ermish May 27 '21 at 09:15
15

you should set document title in the life cycle of 'componentWillMount':

componentWillMount() {
    document.title = 'your title name'
  },

update for hooks:

useEffect(() => {
    document.title = 'current Page Title';
  }, []);
Alvin
  • 298
  • 2
  • 14
15

React Portals can let you render to elements outside the root React node (such at <title>), as if they were actual React nodes. So now you can set the title cleanly and without any additional dependencies:

Here's an example:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

class Title extends Component {
    constructor(props) {
        super(props);
        this.titleEl = document.getElementsByTagName("title")[0];
    }

    render() {
        let fullTitle;
        if(this.props.pageTitle) {
            fullTitle = this.props.pageTitle + " - " + this.props.siteTitle;
        } else {
            fullTitle = this.props.siteTitle;
        }

        return ReactDOM.createPortal(
            fullTitle || "",
            this.titleEl
        );
    }
}
Title.defaultProps = {
    pageTitle: null,
    siteTitle: "Your Site Name Here",
};

export default Title;

Just put the component in the page and set pageTitle:

<Title pageTitle="Dashboard" />
<Title pageTitle={item.name} />
Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
  • Wow, looks so promising, React Helmet and document.title both work, but this is awesome :) Thanks – mamsoudi Mar 08 '19 at 19:23
  • I loved this solution until I realized that it merely appends `fullTitle` to the content already found in index.html's `Default Title`. – JWess Mar 30 '20 at 18:29
  • Just remove default title in your module (not in `constructor`!) ``` import React from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; const titleNode = document.getElementsByTagName("title")[0]; titleNode.innerText = ''; export default class Title extends React.PureComponent { static propTypes = { children: PropTypes.node, }; constructor(props) { super(props); this.el = titleNode; } render() { return ReactDOM.createPortal( this.props.children, this.el, ); } } ``` – Anatoliy Litinskiy May 19 '20 at 18:50
12

Helmet is really a great way of doing it, but for apps that only need to change the title, this is what I use: (modern way React solution - using Hooks)

  1. Create change page title component
import React, { useEffect } from "react";

const ChangePageTitle = ({ pageTitle }) => {
  useEffect(() => {
    const prevTitle = document.title;
    document.title = pageTitle;
    return () => {
      document.title = prevTitle;
    };
  });

  return <></>;
};

export default ChangePageTitle;
  1. Use the component
import ChangePageTitle from "../{yourLocation}/ChangePageTitle";

...

return (
    <>
      <ChangePageTitle pageTitle="theTitleYouWant" />
      ...
    </>
  );

...
10

You have multiple options for this problem I would highly recommend to either use React Helmet or create a hook using useEffect. Instead of writing your own hook, you could also use the one from react-use:

React Helmet

import React from 'react';
import { Helmet } from 'react-helmet';

const MyComponent => () => (
  <Helmet>
    <title>My Title</title>
  </Helmet>
)

react-use

import React from 'react';
import { useTitle } from 'react-use';

const MyComponent = () => {
  useTitle('My Title');

  return null;
}
marcobiedermann
  • 4,317
  • 3
  • 24
  • 37
10

For React v18+, custom hooks will be the simplest approach.

Step 1: Create a hook. (hooks/useDocumentTitle.js)

import { useEffect } from "react";
export const useDocumentTitle = (title) => {

    useEffect(() => {
        document.title = `${title} - WebsiteName`;
    }, [title]);

    return null;
}

Step 2: Call the hook on every page with a custom title according to that page. (pages/HomePage.js)

import { useDocumentTitle } from "../hooks/useDocumentTitle";

const HomePage = () => {
    useDocumentTitle("Website Title For Home Page");
    
    return (
        <>           
            <main>
                <section>Example Text</section>
            </main>            
        </>
    );
}

export { HomePage };

Works well for dynamic pages as well, just pass the product title or whatever content you want to display.

Shubham Sarda
  • 539
  • 5
  • 10
8

Simply you can create a function in a js file and export it for usages in components

like below:

export default function setTitle(title) {
  if (typeof title !== "string") {
     throw new Error("Title should be an string");
  }
  document.title = title;
}

and use it in any component like this:

import React, { Component } from 'react';
import setTitle from './setTitle.js' // no need to js extension at the end

class App extends Component {
  componentDidMount() {
    setTitle("i am a new title");
  }

  render() {
    return (
      <div>
        see the title
      </div>
    );
  }
}

export default App
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
amin msh
  • 472
  • 5
  • 14
6

You can use the following below with document.title = 'Home Page'

import React from 'react'
import { Component } from 'react-dom'


class App extends Component{
  componentDidMount(){
    document.title = "Home Page"
  }

  render(){
    return(
      <p> Title is now equal to Home Page </p>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

or You can use this npm package npm i react-document-title

import React from 'react'
import { Component } from 'react-dom'
import DocumentTitle from 'react-document-title';


class App extends Component{


  render(){
    return(
      <DocumentTitle title='Home'>
        <h1>Home, sweet home.</h1>
      </DocumentTitle>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

Happy Coding!!!

accimeesterlin
  • 4,528
  • 2
  • 25
  • 18
2

I haven't tested this too thoroughly, but this seems to work. Written in TypeScript.

interface Props {
    children: string|number|Array<string|number>,
}

export default class DocumentTitle extends React.Component<Props> {

    private oldTitle: string = document.title;

    componentWillUnmount(): void {
        document.title = this.oldTitle;
    }

    render() {
        document.title = Array.isArray(this.props.children) ? this.props.children.join('') : this.props.children;
        return null;
    }
}

Usage:

export default class App extends React.Component<Props, State> {

    render() {
        return <>
            <DocumentTitle>{this.state.files.length} Gallery</DocumentTitle>
            <Container>
                Lorem ipsum
            </Container>
        </>
    }
}

Not sure why others are keen on putting their entire app inside their <Title> component, that seems weird to me.

By updating the document.title inside render() it'll refresh/stay up to date if you want a dynamic title. It should revert the title when unmounted too. Portals are cute, but seem unnecessary; we don't really need to manipulate any DOM nodes here.

mpen
  • 272,448
  • 266
  • 850
  • 1,236
1

You can use ReactDOM and altering <title> tag

ReactDOM.render(
   "New Title",
   document.getElementsByTagName("title")[0]
);
reza moradi
  • 17
  • 1
  • 5
  • -1 because a separate `ReactDOM.render` cannot interact with any existing state. So this approach have no benefit over `document.title = ...`, unless you only use React to maintain title, which is ... very unusual. In a normal react app, something like `React.createPortal` is needed. Or just simply set `document.title`. – xmcp Feb 11 '22 at 13:34
0

the easiest way is to use react-document-configuration

npm install react-document-configuration --save

Example:

import React from "react";
import Head from "react-document-configuration";

export default function Application() {
    return (
        <div>
            <Head title="HOME" icon="link_of_icon" />
            <div>
                <h4>Hello Developers!</h4>
            </div>
        </div>
    );
};```
Skully
  • 2,882
  • 3
  • 20
  • 31
0

you can create TabTittleHelper.js and

export const TabTittle = (newTitle) => {
document.title=newTitle;
return document.title;
};

later you writed all screens

TabTittle('tittleName');
BCHA
  • 3
  • 4
0

I am not sure if it is a good practice or not, but In index.js headers I put:

document.title="Page Title";
Isabella
  • 137
  • 12
0

I use a simple hook:

export default function usePageTitle(title: string) {
    document.title = `${title} - effOne Hub`;
}

That I then call from each page renderer

export default function About() {
    usePageTitle('About');

    ...

    return <>Page Content</>
}
gtibrett
  • 26
  • 3
  • You don't cleanup the title and "set it back" when component is cleared, not a hook per-se :) – Mugen May 29 '23 at 13:08
-1
const [name, setName] = useState("Jan");
  useEffect(() => 
    {document.title =   "Celebrate " +  {name}.name  ;}
  );
  
  • 3
    It is easier to accept an answer like this if you explain your code example and put it into the context of the question. – chrwahl May 27 '21 at 19:54
  • 1
    `useEffect` was also suggested in [this answer](https://stackoverflow.com/a/56385973/3744182) by [Jordan Daniels](https://stackoverflow.com/users/9009196/jordan-daniels) among others. Might you please [edit] your answer to explain a little how your answer differs from theirs? – dbc May 28 '21 at 04:46
-8

If you're a beginner you can just save yourself from all that by going to the public folder of your react project folder and edit the title in "index.html" and put yours. Don't forget to save so it will reflect.

Stanflows
  • 41
  • 4