A document head manager for React applications enabling dynamic control of HTML head elements
—
Server-side rendering with React Helmet allows you to extract head data after rendering your React app to include in the final HTML document. This is essential for SEO, social media sharing, and prerendering scenarios.
Extract head data after server-side rendering to include in HTML documents.
/**
* Extract head data after server-side rendering
* Must be called on server after ReactDOMServer.renderToString() or renderToStaticMarkup()
* @returns HelmetData object containing all head elements and attributes
*/
static renderStatic(): HelmetData;
/**
* Legacy alias for renderStatic()
* @deprecated Use renderStatic() instead
* @returns HelmetData object containing all head elements and attributes
*/
static rewind(): HelmetData;
interface HelmetData {
/** Document title element */
title: HelmetElement;
/** Base element */
base: HelmetElement;
/** Meta elements */
meta: HelmetElement;
/** Link elements */
link: HelmetElement;
/** Script elements */
script: HelmetElement;
/** Style elements */
style: HelmetElement;
/** Noscript elements */
noscript: HelmetElement;
/** HTML element attributes */
htmlAttributes: HelmetElement;
/** Body element attributes */
bodyAttributes: HelmetElement;
}
interface HelmetElement {
/**
* Convert to React components for JSX rendering
* @returns Array of React elements
*/
toComponent(): React.ReactElement[];
/**
* Convert to HTML string for server-side rendering
* @returns HTML string representation
*/
toString(): string;
}Usage Example:
import React from "react";
import ReactDOMServer from "react-dom/server";
import { Helmet } from "react-helmet";
import App from "./App";
// Render your app
const appString = ReactDOMServer.renderToString(<App />);
// Extract head data
const helmet = Helmet.renderStatic();
// Generate complete HTML
const html = `
<!DOCTYPE html>
<html ${helmet.htmlAttributes.toString()}>
<head>
${helmet.title.toString()}
${helmet.meta.toString()}
${helmet.link.toString()}
${helmet.script.toString()}
${helmet.style.toString()}
</head>
<body ${helmet.bodyAttributes.toString()}>
<div id="root">${appString}</div>
${helmet.noscript.toString()}
</body>
</html>
`;When using JSX for server-side HTML generation, use the toComponent() method:
import React from "react";
import ReactDOMServer from "react-dom/server";
import { Helmet } from "react-helmet";
function HTMLDocument() {
// App must be rendered first to populate Helmet state
const appString = ReactDOMServer.renderToString(<App />);
const helmet = Helmet.renderStatic();
const htmlAttrs = helmet.htmlAttributes.toComponent();
const bodyAttrs = helmet.bodyAttributes.toComponent();
return (
<html {...htmlAttrs}>
<head>
{helmet.title.toComponent()}
{helmet.meta.toComponent()}
{helmet.link.toComponent()}
{helmet.script.toComponent()}
{helmet.style.toComponent()}
</head>
<body {...bodyAttrs}>
<div id="root" dangerouslySetInnerHTML={{ __html: appString }} />
{helmet.noscript.toComponent()}
</body>
</html>
);
}Get current Helmet state for testing without affecting the instance stack.
/**
* Testing utility to get current state without resetting the mounted instance stack
* @returns Current HelmetData state
* @note Only use for testing purposes
*/
static peek(): HelmetData;Usage in Tests:
import { Helmet } from "react-helmet";
import { render } from "@testing-library/react";
test("helmet sets correct title", () => {
render(
<Helmet>
<title>Test Title</title>
</Helmet>
);
const helmetData = Helmet.peek();
expect(helmetData.title.toString()).toContain("Test Title");
});Control DOM usage detection for server environments.
/**
* Controls DOM usage detection
* Set to false in server environments where DOM is not available
* @param value - Boolean indicating if DOM can be used
*/
static set canUseDOM(value: boolean);Usage:
import { Helmet } from "react-helmet";
// In server environment
Helmet.canUseDOM = false;
// In browser environment (default)
Helmet.canUseDOM = true;Here's a complete Express.js server example:
import express from "express";
import React from "react";
import ReactDOMServer from "react-dom/server";
import { Helmet } from "react-helmet";
import App from "./App";
const app = express();
// Configure Helmet for server environment
Helmet.canUseDOM = false;
app.get("*", (req, res) => {
// Render the app
const appString = ReactDOMServer.renderToString(
<App url={req.url} />
);
// Extract head data
const helmet = Helmet.renderStatic();
// Send complete HTML
res.send(`
<!DOCTYPE html>
<html ${helmet.htmlAttributes.toString()}>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
${helmet.title.toString()}
${helmet.meta.toString()}
${helmet.link.toString()}
${helmet.script.toString()}
${helmet.style.toString()}
</head>
<body ${helmet.bodyAttributes.toString()}>
<div id="root">${appString}</div>
${helmet.noscript.toString()}
<script src="/client.js"></script>
</body>
</html>
`);
});
app.listen(3000);Critical: Always call renderStatic() or rewind() on the server to prevent memory leaks. React Helmet tracks mounted instances, and failing to extract the data will cause memory accumulation.
// ❌ Memory leak - renderStatic() never called
app.get("/", (req, res) => {
const html = ReactDOMServer.renderToString(<App />);
res.send(`<html><body>${html}</body></html>`);
});
// ✅ Correct - renderStatic() extracts and clears state
app.get("/", (req, res) => {
const html = ReactDOMServer.renderToString(<App />);
const helmet = Helmet.renderStatic();
res.send(`<html><body>${html}</body></html>`);
});When using prebuilt app compilations, ensure the same react-helmet instance is used:
// webpack.config.js
module.exports = {
externals: ["react-helmet"],
// ... other config
};Control HTML entity encoding for server-side rendering:
<Helmet encodeSpecialCharacters={false}>
<title>Title with <special> characters</title>
</Helmet>
// With encodeSpecialCharacters={true} (default):
// <title>Title with <special> characters</title>
// With encodeSpecialCharacters={false}:
// <title>Title with <special> characters</title>Install with Tessl CLI
npx tessl i tessl/npm-react-helmet