<title>
Sets the document title shown in the browser tab and search results, hoisted into the head.
<title>My Blog</title>- Added in React 19.0.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$children | string | Text only. A single string, or a single number or object with a toString method. Multiple children are not allowed. |
$itemPropoptional | string | Marks the element as metadata about a specific part of the page. Its presence disables all special title behaviour. |
Return value
Renders nothing visible. React places the <title> DOM node in the document <head>, setting the browser tab and the title crawlers read.
Errors
Passing more than one child raises an error: <title>Page {n}</title> is a two-element array, so interpolate into a single template string instead.
Changelog
- PHP 19.0.0<title> rendered anywhere in the React tree is hoisted into the document <head>. Before 19 it rendered in place and you set the tab title with document.title in an effect, or with a library.
Render a <title> from any component and React puts it in the document <head>, which sets the browser tab, the bookmark name and the headline a search engine shows. It replaces the old pattern of writing document.title inside an effect: because the title travels with the component, it is set during a server render too, so crawlers and link unfurlers see it without executing JavaScript.
One string, and only one title
The child must be a single text node. <title>Page {n}</title> is two children — a string and a number — and errors; write <title>{`Page ${n}`}</title>. React also does not merge or de-duplicate titles. If a layout and a route both render one, both land in the head and the result is undefined: browsers generally show the first, crawlers may not agree. Pick one owner per page.
What trips people up
Two contexts opt out of hoisting entirely. A <title> inside an <svg> is an accessibility label for the graphic and stays there, and a <title> carrying itemProp is structured data about a page fragment. Both render in place. Note also that the title prop on a normal element is unrelated — that is a hover tooltip.
Example
function PageTitle({ page, suffix = "Acme" }) {
// One child only: build the whole string before interpolating.
return <title>{`${page} – ${suffix}`}</title>;
}
function InvoiceList({ invoices, unpaid }) {
return (
<section>
{/* Only this component owns the title for the page. */}
<PageTitle page={unpaid > 0 ? `Invoices (${unpaid})` : "Invoices"} />
<meta name="description" content="Outstanding and settled invoices." />
<h1>Invoices</h1>
<ul>
{invoices.map((invoice) => (
<li key={invoice.id}>
{invoice.id} - {invoice.status}
</li>
))}
</ul>
</section>
);
}
export default function InvoicesPage() {
const invoices = [
{ id: "INV-1041", status: "unpaid" },
{ id: "INV-1040", status: "paid" },
{ id: "INV-1039", status: "unpaid" }
];
const unpaid = invoices.filter((i) => i.status === "unpaid").length;
return <InvoicesPage_Inner invoices={invoices} unpaid={unpaid} />;
}
function InvoicesPage_Inner({ invoices, unpaid }) {
return <InvoiceList invoices={invoices} unpaid={unpaid} />;
}When to use it
- Setting the tab title from the route component, including on the server-rendered response
- Building a template title such as "Invoices - Acme" from data the page already has
- Showing an unread count or dirty-state marker in the tab while the user is elsewhere
- Reflecting a search query or record name so browser history entries are distinguishable
Frequently asked questions
How do I set the page title in React 19?
Render <title>Your title</title> from the component that owns the page; React hoists it into <head>. This works during server rendering too, so the title is present in the HTML response rather than being patched in by an effect after hydration. Only one component should render a title for any given page.
Why does interpolating a variable into title throw an error?
Because <title>Page {n}</title> passes two children — the literal string and the value — and <title> accepts exactly one text child. Build the full string first: <title>{`Page ${n}`}</title>. A single number or an object with a toString method is also accepted; an element, a fragment, or two expressions side by side is not.
Do I still need document.title or react-helmet?
No, for setting a title React 19 handles it natively and does so during server rendering, which document.title in an effect cannot. Reach for a helmet-style library only if you depend on its de-duplication and override rules, since React does not merge competing titles — render two and both end up in the head.
More examples
The interpolation error, and the fix
BrokenTitle throws, because JSX turns the tag's contents into an array of two children and <title> accepts exactly one text node. The tab reads "Results page 3" once you use the template-string form. The same rule bites when you try to compose a title from pieces — concatenate in JavaScript first rather than putting two expressions side by side inside the tag.
function BrokenTitle({ pageNumber }) {
// Error: this is two children, a string and a number.
return <title>Results page {pageNumber}</title>;
}
function WorkingTitle({ pageNumber }) {
// One string child.
return <title>{`Results page ${pageNumber}`}</title>;
}
export default function ResultsPage() {
return (
<main>
<WorkingTitle pageNumber={3} />
<h1>Results</h1>
<p>Page 3 of 8</p>
</main>
);
}Two titles, and where the responsibility belongs
With BadLayout the head ends up holding two <title> nodes, since React neither merges nor replaces them; browsers usually display the first, crawlers may pick either, and nothing warns you. The corrected split puts document-wide tags that no page will restate in the layout and leaves the title to whichever component actually knows what the page is. If you want a shared suffix, pass it down and build the full string in one place.
// Wrong: the layout and the page both claim the title.
function BadLayout({ children }) {
return (
<div>
<title>Acme</title>
{children}
</div>
);
}
// Right: the layout owns tags no page will restate; the page owns the title.
function Layout({ children }) {
return (
<div>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{children}
</div>
);
}
function SettingsPage() {
return (
<>
<title>Settings – Acme</title>
<h1>Settings</h1>
</>
);
}
export default function App() {
return (
<Layout>
<SettingsPage />
</Layout>
);
}An SVG title is not a document title
The browser tab is untouched. A <title> inside an <svg> is one of the two documented exceptions to hoisting — it is the graphic's accessible name, read by screen readers and shown as a tooltip on hover, so moving it to <head> would both break the label and hijack the page title. The other exception is a <title> with an itemProp, which is treated as structured data about part of the page.
export default function StatusIcon() {
return (
<p>
Build status:{" "}
<svg width="16" height="16" viewBox="0 0 16 16" role="img">
{/* Stays inside the svg: this is the accessible name for the graphic. */}
<title>Passing</title>
<circle cx="8" cy="8" r="7" fill="#16a34a" />
</svg>
</p>
);
}
Discussion