Handling CSS-in-JS Libraries
Handling CSS-in-JS Libraries
Many React applications use CSS-in-JS libraries like styled-components or emotion, which dynamically inject styles. These libraries require specific CSP configurations:
// Styled-components with CSP
import { createGlobalStyle } from 'styled-components';
// Configure styled-components to use nonce
const GlobalStyle = createGlobalStyle`
body {
margin: 0;
padding: 0;
}
`;
// App.js - Passing nonce to styled-components
function App() {
// Get nonce from server-injected global variable
const nonce = window.__CSP_NONCE__;
return (
<StyleSheetManager nonce={nonce}>
<GlobalStyle />
<YourAppComponents />
</StyleSheetManager>
);
}
// Server-side rendering with styled-components
import { ServerStyleSheet } from 'styled-components';
app.get('*', (req, res) => {
const sheet = new ServerStyleSheet();
const nonce = res.locals.nonce;
try {
const html = ReactDOMServer.renderToString(
sheet.collectStyles(
<StyleSheetManager nonce={nonce}>
<App />
</StyleSheetManager>
)
);
const styleTags = sheet.getStyleTags(); // Get style tags with nonce
const finalHtml = indexHtml
.replace('</head>', `${styleTags}</head>`)
.replace('<div id="root"></div>', `<div id="root">${html}</div>`);
res.send(finalHtml);
} finally {
sheet.seal();
}
});
For Emotion library:
// emotion-cache.js
import createCache from '@emotion/cache';
export const createEmotionCache = (nonce) => {
return createCache({
key: 'css',
nonce: nonce,
});
};
// _app.js (Next.js example)
import { CacheProvider } from '@emotion/react';
import { createEmotionCache } from '../utils/emotion-cache';
function MyApp({ Component, pageProps, emotionCache = createEmotionCache() }) {
return (
<CacheProvider value={emotionCache}>
<Component {...pageProps} />
</CacheProvider>
);
}
// Server-side configuration
MyApp.getInitialProps = async (appContext) => {
const nonce = appContext.ctx.res.locals.nonce;
const emotionCache = createEmotionCache(nonce);
const appProps = await App.getInitialProps(appContext);
return { ...appProps, emotionCache };
};