or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

create-instance.mdextract-critical.mdindex.mdrender-to-stream.mdrender-to-string.md
tile.json

render-to-string.mddocs/

String-based CSS Inlining

String-based CSS inlining functionality that directly injects critical CSS as <style> tags into HTML strings, providing immediate server-side rendering optimization.

Capabilities

renderStylesToString Function

Inlines critical CSS directly into HTML strings by parsing Emotion class names and injecting corresponding styles as <style> tags at appropriate positions.

/**
 * Inlines critical CSS directly into HTML string
 * @param html - Server-rendered HTML string containing Emotion class names
 * @returns HTML string with critical CSS inlined as <style> tags
 */
function renderStylesToString(html: string): string;

Usage Examples:

import React from "react";
import { renderToString } from "react-dom/server";
import { renderStylesToString } from "@emotion/server";
import styled from "@emotion/styled";

const Button = styled.button`
  background: blue;
  color: white;
  padding: 10px 20px;
`;

const Header = styled.h1`
  font-size: 24px;
  margin: 0;
`;

const App = () => (
  <div>
    <Header>Welcome</Header>
    <Button>Click me</Button>
  </div>
);

// Inline critical CSS
const htmlWithStyles = renderStylesToString(renderToString(<App />));

console.log(htmlWithStyles);
// Output includes:
// <style data-emotion="css abc123 def456">
//   /* CSS for Button and Header components */
// </style>
// <div>
//   <h1 class="css-def456">Welcome</h1>
//   <button class="css-abc123">Click me</button>
// </div>

Style Tag Generation

The function generates <style> tags with specific attributes:

  • data-emotion: Contains the cache key and space-separated style IDs
  • nonce: Security nonce if configured in the cache
  • CSS content: Actual CSS rules for the detected styles

Example with Nonce:

import createEmotionServer from "@emotion/server/create-instance";
import createCache from "@emotion/cache";

// Create cache with nonce for Content Security Policy
const cache = createCache({
  key: "css",
  nonce: "random-nonce-value"
});

const { renderStylesToString } = createEmotionServer(cache);

const htmlWithStyles = renderStylesToString(renderToString(<App />));
// Generated style tag includes: nonce="random-nonce-value"

Processing Strategy

The inlining process follows a sophisticated strategy:

  1. Global Styles First: Unregistered styles are injected at the beginning
  2. Component-Specific Styles: Styles are injected just before their first usage
  3. Deduplication: Each style is only included once, even if used multiple times
  4. Order Preservation: Maintains CSS cascade order for consistent styling

Advanced Usage with Multiple Components:

import React from "react";
import { renderToString } from "react-dom/server";
import { renderStylesToString } from "@emotion/server";
import styled from "@emotion/styled";

const GlobalStyle = styled.div`
  font-family: Arial, sans-serif;
  * {
    box-sizing: border-box;
  }
`;

const Card = styled.div`
  background: white;
  border: 1px solid #ccc;
  border-radius: 8px;
  padding: 16px;
`;

const Title = styled.h2`
  color: #333;
  margin: 0 0 16px 0;
`;

const App = () => (
  <GlobalStyle>
    <Card>
      <Title>Card Title</Title>
      <p>Card content goes here.</p>
    </Card>
  </GlobalStyle>
);

const htmlWithStyles = renderStylesToString(renderToString(<App />));
// Results in optimally ordered and deduplicated CSS injection

Integration Patterns

Express.js Server:

import express from "express";
import React from "react";
import { renderToString } from "react-dom/server";
import { renderStylesToString } from "@emotion/server";

const app = express();

app.get("/", (req, res) => {
  const htmlWithStyles = renderStylesToString(renderToString(<App />));
  
  const fullPage = `
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>My App</title>
    </head>
    <body>
      <div id="root">${htmlWithStyles}</div>
    </body>
    </html>
  `;
  
  res.send(fullPage);
});

Next.js Custom Document:

import Document, { Html, Head, Main, NextScript } from "next/document";
import { renderStylesToString } from "@emotion/server";

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const originalRenderPage = ctx.renderPage;

    ctx.renderPage = () =>
      originalRenderPage({
        enhanceApp: (App) => (props) => renderStylesToString(<App {...props} />),
      });

    const initialProps = await Document.getInitialProps(ctx);
    return initialProps;
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

Performance Considerations

  • String Operations: Uses efficient string manipulation for large HTML documents
  • Memory Usage: Processes HTML in a single pass to minimize memory overhead
  • CSS Optimization: Automatically removes duplicate styles and unused CSS
  • Cache Efficiency: Leverages Emotion's cache for fast style lookup