or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

compatibility.mdcore-tss-api.mdcss-utilities.mddsfr-integration.mdglobal-styles-keyframes.mdindex.mdmakestyles-api.mdmui-integration.mdnextjs-ssr.mdwithstyles-hoc.md

nextjs-ssr.mddocs/

0

# Next.js SSR Support

1

2

TSS-React provides comprehensive server-side rendering utilities for Next.js applications, supporting both the modern App Router and traditional Pages Router patterns. The integration ensures proper CSS extraction, hydration, and cache management for optimal performance.

3

4

## Capabilities

5

6

### App Router Support (Next.js 13+)

7

8

Emotion cache provider specifically designed for Next.js App Router with `useServerInsertedHTML` integration.

9

10

```typescript { .api }

11

/**

12

* Emotion cache provider for Next.js App Router

13

* @param props - Configuration props for cache provider

14

* @returns JSX element providing emotion cache to component tree

15

*/

16

function NextAppDirEmotionCacheProvider(

17

props: NextAppDirEmotionCacheProviderProps

18

): JSX.Element;

19

20

interface NextAppDirEmotionCacheProviderProps {

21

/** Options passed to createCache() from @emotion/cache */

22

options: Omit<OptionsOfCreateCache, "insertionPoint"> & {

23

/** Whether to prepend styles with @layer emotion for CSS cascade control */

24

prepend?: boolean;

25

};

26

/** Custom CacheProvider component, defaults to @emotion/react CacheProvider */

27

CacheProvider?: React.Provider<EmotionCache>;

28

/** Child components */

29

children: ReactNode;

30

}

31

32

interface OptionsOfCreateCache {

33

/** Cache key for style identification */

34

key: string;

35

/** Nonce for Content Security Policy */

36

nonce?: string;

37

/** Style container element */

38

container?: HTMLElement;

39

/** Whether styles are speedy (no text content) */

40

speedy?: boolean;

41

}

42

```

43

44

**Usage Examples:**

45

46

```typescript

47

// app/layout.tsx

48

import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";

49

50

export default function RootLayout({

51

children,

52

}: {

53

children: React.ReactNode;

54

}) {

55

return (

56

<html lang="en">

57

<body>

58

<NextAppDirEmotionCacheProvider

59

options={{

60

key: "css",

61

prepend: true // Optional: wrap styles in @layer emotion

62

}}

63

>

64

{children}

65

</NextAppDirEmotionCacheProvider>

66

</body>

67

</html>

68

);

69

}

70

71

// With custom nonce for CSP

72

export default function SecureLayout({

73

children,

74

}: {

75

children: React.ReactNode;

76

}) {

77

return (

78

<html lang="en">

79

<body>

80

<NextAppDirEmotionCacheProvider

81

options={{

82

key: "css",

83

nonce: process.env.CSP_NONCE,

84

prepend: true

85

}}

86

>

87

{children}

88

</NextAppDirEmotionCacheProvider>

89

</body>

90

</html>

91

);

92

}

93

94

// app/page.tsx - Using TSS-React in App Router

95

import { tss } from "tss-react";

96

97

const useStyles = tss.create({

98

container: {

99

padding: "2rem",

100

backgroundColor: "#f5f5f5",

101

minHeight: "100vh"

102

},

103

title: {

104

fontSize: "2rem",

105

fontWeight: "bold",

106

color: "#333",

107

marginBottom: "1rem"

108

}

109

});

110

111

export default function HomePage() {

112

const { classes } = useStyles();

113

114

return (

115

<div className={classes.container}>

116

<h1 className={classes.title}>Welcome to Next.js App Router with TSS-React</h1>

117

</div>

118

);

119

}

120

```

121

122

### Pages Router Support (Next.js 12 and earlier)

123

124

Advanced SSR approach for Next.js Pages Router with proper critical CSS extraction and hydration.

125

126

```typescript { .api }

127

/**

128

* Creates SSR utilities for Next.js Pages Router

129

* @param options - Emotion cache options

130

* @param CacheProvider - Optional custom cache provider component

131

* @returns Object containing App and Document enhancement functions

132

*/

133

function createEmotionSsrAdvancedApproach(

134

options: Omit<OptionsOfCreateCache, "insertionPoint"> & {

135

/** Whether to prepend styles for CSS cascade control */

136

prepend?: boolean;

137

},

138

CacheProvider?: Function

139

): {

140

/**

141

* Higher-order component for _app.js

142

* @param App - Next.js App component

143

* @returns Enhanced App component with emotion cache

144

*/

145

withAppEmotionCache<AppComponent extends NextComponentType<any, any, any>>(

146

App: AppComponent

147

): AppComponent;

148

149

/**

150

* Augments _document.js for SSR critical CSS extraction

151

* @param Document - Next.js Document component

152

*/

153

augmentDocumentWithEmotionCache(

154

Document: NextComponentType<any, any, any>

155

): void;

156

};

157

158

type NextComponentType<Context = any, InitialProps = {}, Props = {}> = ComponentType<Props> & {

159

getInitialProps?(context: Context): InitialProps | Promise<InitialProps>;

160

};

161

```

162

163

**Usage Examples:**

164

165

```typescript

166

// utils/ssr.ts

167

import { createEmotionSsrAdvancedApproach } from "tss-react/next/pagesDir";

168

169

export const { withAppEmotionCache, augmentDocumentWithEmotionCache } =

170

createEmotionSsrAdvancedApproach({

171

key: "css",

172

prepend: true // Optional: control CSS precedence

173

});

174

175

// pages/_app.tsx

176

import type { AppProps } from "next/app";

177

import { withAppEmotionCache } from "../utils/ssr";

178

179

function MyApp({ Component, pageProps }: AppProps) {

180

return <Component {...pageProps} />;

181

}

182

183

export default withAppEmotionCache(MyApp);

184

185

// pages/_document.tsx

186

import Document, { Html, Head, Main, NextScript } from "next/document";

187

import { augmentDocumentWithEmotionCache } from "../utils/ssr";

188

189

augmentDocumentWithEmotionCache(Document);

190

191

export default class MyDocument extends Document {

192

render() {

193

return (

194

<Html lang="en">

195

<Head />

196

<body>

197

<Main />

198

<NextScript />

199

</body>

200

</Html>

201

);

202

}

203

}

204

205

// pages/index.tsx - Using TSS-React in Pages Router

206

import { tss } from "tss-react";

207

208

const useStyles = tss.create({

209

container: {

210

padding: "2rem",

211

backgroundColor: "#f0f8ff",

212

minHeight: "100vh"

213

},

214

title: {

215

fontSize: "2.5rem",

216

fontWeight: "700",

217

color: "#1a365d",

218

textAlign: "center",

219

marginBottom: "2rem"

220

},

221

card: {

222

backgroundColor: "white",

223

borderRadius: "8px",

224

padding: "1.5rem",

225

boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",

226

maxWidth: "600px",

227

margin: "0 auto"

228

}

229

});

230

231

export default function HomePage() {

232

const { classes } = useStyles();

233

234

return (

235

<div className={classes.container}>

236

<h1 className={classes.title}>Pages Router with TSS-React</h1>

237

<div className={classes.card}>

238

<p>This page demonstrates server-side rendering with critical CSS extraction.</p>

239

</div>

240

</div>

241

);

242

}

243

```

244

245

### MUI Integration with Next.js

246

247

Combining MUI theme support with Next.js SSR for complete styling solutions.

248

249

```typescript

250

// App Router with MUI (app/layout.tsx)

251

import { ThemeProvider, createTheme } from "@mui/material/styles";

252

import CssBaseline from "@mui/material/CssBaseline";

253

import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";

254

255

const theme = createTheme({

256

palette: {

257

mode: "light",

258

primary: { main: "#1976d2" },

259

secondary: { main: "#dc004e" }

260

}

261

});

262

263

export default function RootLayout({

264

children,

265

}: {

266

children: React.ReactNode;

267

}) {

268

return (

269

<html lang="en">

270

<body>

271

<NextAppDirEmotionCacheProvider options={{ key: "css" }}>

272

<ThemeProvider theme={theme}>

273

<CssBaseline />

274

{children}

275

</ThemeProvider>

276

</NextAppDirEmotionCacheProvider>

277

</body>

278

</html>

279

);

280

}

281

282

// Pages Router with MUI

283

// utils/mui-ssr.ts

284

import { createEmotionSsrAdvancedApproach } from "tss-react/next/pagesDir";

285

286

export const { withAppEmotionCache, augmentDocumentWithEmotionCache } =

287

createEmotionSsrAdvancedApproach({ key: "css" });

288

289

// pages/_app.tsx

290

import type { AppProps } from "next/app";

291

import { ThemeProvider, createTheme } from "@mui/material/styles";

292

import CssBaseline from "@mui/material/CssBaseline";

293

import { withAppEmotionCache } from "../utils/mui-ssr";

294

295

const theme = createTheme({

296

palette: {

297

primary: { main: "#2196f3" },

298

secondary: { main: "#f50057" }

299

}

300

});

301

302

function MyApp({ Component, pageProps }: AppProps) {

303

return (

304

<ThemeProvider theme={theme}>

305

<CssBaseline />

306

<Component {...pageProps} />

307

</ThemeProvider>

308

);

309

}

310

311

export default withAppEmotionCache(MyApp);

312

313

// Component using MUI integration

314

import { tss } from "tss-react/mui";

315

import { Button, Paper, Typography } from "@mui/material";

316

317

const useStyles = tss.create(({ theme }) => ({

318

paper: {

319

padding: theme.spacing(3),

320

margin: theme.spacing(2),

321

backgroundColor: theme.palette.background.paper,

322

borderRadius: theme.shape.borderRadius

323

},

324

title: {

325

color: theme.palette.primary.main,

326

marginBottom: theme.spacing(2)

327

},

328

button: {

329

marginTop: theme.spacing(2),

330

backgroundImage: `linear-gradient(45deg, ${theme.palette.primary.main} 30%, ${theme.palette.secondary.main} 90%)`,

331

color: "white"

332

}

333

}));

334

335

function MuiComponent() {

336

const { classes } = useStyles();

337

338

return (

339

<Paper className={classes.paper}>

340

<Typography variant="h4" className={classes.title}>

341

MUI + TSS-React + Next.js

342

</Typography>

343

<Typography variant="body1">

344

This demonstrates the complete integration of MUI theming with TSS-React in Next.js SSR.

345

</Typography>

346

<Button variant="contained" className={classes.button}>

347

Styled Button

348

</Button>

349

</Paper>

350

);

351

}

352

```

353

354

### Advanced SSR Configuration

355

356

#### Custom Cache Configuration

357

358

```typescript

359

import createCache from "@emotion/cache";

360

import { createEmotionSsrAdvancedApproach } from "tss-react/next/pagesDir";

361

362

// Custom cache with specific configuration

363

const customCache = createCache({

364

key: "my-app",

365

nonce: process.env.CSP_NONCE,

366

speedy: process.env.NODE_ENV === "production"

367

});

368

369

export const { withAppEmotionCache, augmentDocumentWithEmotionCache } =

370

createEmotionSsrAdvancedApproach(

371

{

372

key: "my-app",

373

nonce: process.env.CSP_NONCE,

374

prepend: true

375

}

376

);

377

```

378

379

#### Content Security Policy Integration

380

381

```typescript

382

// next.config.js

383

const ContentSecurityPolicy = `

384

default-src 'self';

385

script-src 'self' 'nonce-${process.env.CSP_NONCE}';

386

style-src 'self' 'nonce-${process.env.CSP_NONCE}' 'unsafe-inline';

387

img-src 'self' data: https:;

388

`;

389

390

module.exports = {

391

async headers() {

392

return [

393

{

394

source: "/(.*)",

395

headers: [

396

{

397

key: "Content-Security-Policy",

398

value: ContentSecurityPolicy.replace(/\s{2,}/g, " ").trim()

399

}

400

]

401

}

402

];

403

}

404

};

405

406

// app/layout.tsx with CSP nonce

407

import { NextAppDirEmotionCacheProvider } from "tss-react/next/appDir";

408

409

export default function RootLayout({

410

children,

411

}: {

412

children: React.ReactNode;

413

}) {

414

return (

415

<html lang="en">

416

<body>

417

<NextAppDirEmotionCacheProvider

418

options={{

419

key: "css",

420

nonce: process.env.CSP_NONCE

421

}}

422

>

423

{children}

424

</NextAppDirEmotionCacheProvider>

425

</body>

426

</html>

427

);

428

}

429

```

430

431

#### Performance Optimization

432

433

```typescript

434

// Production-optimized SSR setup

435

import { createEmotionSsrAdvancedApproach } from "tss-react/next/pagesDir";

436

437

export const { withAppEmotionCache, augmentDocumentWithEmotionCache } =

438

createEmotionSsrAdvancedApproach({

439

key: "css",

440

speedy: true, // Enable speedy mode for production

441

prepend: true, // Ensure proper CSS cascade

442

nonce: process.env.CSP_NONCE

443

});

444

445

// pages/_document.tsx with optimization

446

import Document, { Html, Head, Main, NextScript, DocumentContext } from "next/document";

447

import { augmentDocumentWithEmotionCache } from "../utils/ssr";

448

449

augmentDocumentWithEmotionCache(Document);

450

451

export default class MyDocument extends Document {

452

static async getInitialProps(ctx: DocumentContext) {

453

const initialProps = await Document.getInitialProps(ctx);

454

return initialProps;

455

}

456

457

render() {

458

return (

459

<Html lang="en">

460

<Head>

461

{/* Preload critical resources */}

462

<link rel="preconnect" href="https://fonts.googleapis.com" />

463

<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />

464

</Head>

465

<body>

466

<Main />

467

<NextScript />

468

</body>

469

</Html>

470

);

471

}

472

}

473

```

474

475

### Migration and Compatibility

476

477

#### From @emotion/styled SSR

478

479

```typescript

480

// Before: Manual emotion SSR setup

481

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

482

import createCache from "@emotion/cache";

483

484

// After: TSS-React automated setup

485

import { createEmotionSsrAdvancedApproach } from "tss-react/next/pagesDir";

486

487

export const { withAppEmotionCache, augmentDocumentWithEmotionCache } =

488

createEmotionSsrAdvancedApproach({

489

key: "css",

490

prepend: true

491

});

492

```

493

494

#### Troubleshooting Common Issues

495

496

```typescript

497

// Issue: Styles not being extracted on server

498

// Solution: Ensure Document is properly augmented

499

// pages/_document.tsx

500

import Document from "next/document";

501

import { augmentDocumentWithEmotionCache } from "../utils/ssr";

502

503

// This MUST be called before the class definition

504

augmentDocumentWithEmotionCache(Document);

505

506

export default class MyDocument extends Document {

507

// Document implementation

508

}

509

510

// Issue: CSS precedence problems

511

// Solution: Use prepend option to control cascade

512

export const { withAppEmotionCache, augmentDocumentWithEmotionCache } =

513

createEmotionSsrAdvancedApproach({

514

key: "css",

515

prepend: true // Ensures TSS styles come first

516

});

517

518

// Issue: Hydration mismatches

519

// Solution: Ensure cache key consistency between server and client

520

const cacheKey = "tss-react-css";

521

522

export const { withAppEmotionCache, augmentDocumentWithEmotionCache } =

523

createEmotionSsrAdvancedApproach({

524

key: cacheKey, // Same key used on both server and client

525

prepend: true

526

});

527

```