When using server side rendering, and applying configureLoadStyles((styles) => {})
, I receive this warning/error in console, which results in CSS not being applied to my component(s):
Warning: Prop 'className' did not match. Server: "_2bi0E" Client: "styles__header-2bi0E"
I'm trying to work with ReactJS.Net for server rendering, but this is a major issue I'm encountering atm.
_edit_: I tried using https://barbar.github.io/vortigern/ ReactJS project template, which has server side rendering included in it, but with the same result. Will try again tomorrow with a more _minimal_ project setup and see if i get the same issue once more.
+1 I am using this with Next.js but having same problem with @NickSevens.
Seems I copied the wrong error message here. The one I got was:
Warning: Prop className did not match. Server: "ms-Label root-0" Client: "ms-Label root-32"
@dzearing did you have a chance to look at this? @NickSevens opened two issues, so we should figure out whether this is OUIFR or load-themed-styles, and close one of the issues.
Hey guys, any update on this? Tnx!
I also get this problem, any update? Thanks.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions to Fabric React!
Any update on this?
Sorry, yes. We are making some improvements in ssr rendering, tracking in #616.
I'm a little concerned that this isn't straightforward to fix. I am not sure exactly why react cares that the classnames match at all.
Hi
Having the same issue , the warning is this:
Warning: Prop
iddid not match. Server: "TextField10" Client: "TextField0"
The problem that i got is the styles not applying to the components.
up
@omidnavy I had the same problem. After a little investigation, I found the function that causes the issue:
https://github.com/OfficeDev/office-ui-fabric-react/blob/master/packages/utilities/src/object.ts#L94
It uses a global incrementing counter (window
on client or process
on server). To reset, add the following to somewhere that runs before every render:
process.__currentId__ = 0
__currentId__ in a server is no more stored under process. I am not sure if it ever was.
I also faced the problem where the classNames generated by server and client didn't match.
After, a little bit of digging the source code found this method resetIds,
https://github.com/OfficeDev/office-ui-fabric-react/blob/master/packages/utilities/src/getId.ts
After calling this as given above, it fixed the issue for me.
import { resetIds } from '@uifabric/utilities';
Call the following method just before every page is rendered. In my case, I was using nextjs, so I called this method on render method of Document.
resetIds(1);
Update: After fixing this, the page loaded fine but the styles were being regenerated in the client-side. So, the screen was annoyingly flickered. Probably not related to the original issue, but eventually, this may come as a side-effect.
During debugging, I found that the configureLoadStyles method was not being called for the styles created by styled-components(using styled API). So, I had to wire-up insertRule event on Stylesheet to loadStyles method like shown below,
import { loadStyles } from '@microsoft/load-themed-styles';
import { Stylesheet } from '@uifabric/merge-styles';
const styleSheet = Stylesheet.getInstance();
styleSheet.setConfig({
onInsertRule: (rule) => {
loadStyles(rule);
}
});
Now all the styles are being rendered properly and the pages also doesn't flicker anymore.
But, I am not sure about one thing is whether is this the expected way to use fabric react in server-rendered apps.
The problem is still there.
@dzearing or other contributors (@khmakoto maybe?) Hi! Thanks for your effort on SSR.
So, we think we can make due with what's at the wiki since we really want to try using Fluent UI and we're using Next, but I would love to see this work taken to slightly more solid ground. This issue on this ticket (className did not match
) has been open for 2 1/2 years now, and TBH it erodes our team's confidence in using Fluent UI with Next. Other frameworks have fought this issue, and some have successfully solved it
Also wanted to point out that as popular as Next is, their repo currently lacks a Fluent-UI example but has examples for many others.
Material UI has done a really good job documenting how their SSR process works. I notice that they and a few related frameworks recommend doing an additional cleanup step of deleting server-generated styles after the live JS/CSS are ready. I've tried this same technique with Fluent and it doesn't work well, but maybe that's a good thing in that Fluent is overlaying partial themes as an optimization? If so that's cool, but it's not really made clear in your docs.
It would be great if it your example were provided as Typescript. I was thrown off by a type error which cost me some time, thinking your example was outdated. Turns out it needed a typing, since you're injecting an unknown field.
export default class MyDocument extends Document<{ styleTags: string }> {
I'd love some explanation in the docs as to what you're doing in there, for example stylesheet.reset() and resetIds(), why are those done?
Also wanted to mention that the right place to put the theme providing tags is not in a page like index.tsx, but rather in the _app.tsx wrapper
. I've tried this and it works, but this quickly leads me to want a context-based solution like theThemeProvider
package in the fluent repo. That package does not work with SSR however, throws 500 (Internal Server Error) / at WeakMap.set (<anonymous>) / at Object.exports.registerStyles
, so we'll try to roll our own.
We think we can proceed with Fluent UI in our project but wanted to remind you guys of this ticket and say that sprucing up SSR support would really be a great bonus for us! Thanks again for your work, and sorry for the long post.
@dzearing CSS may not be injecting properly server-side.
Here's a screenshot of what I'm seeing in Chrome using the Performance tool:
I rewrote the script based on the Material UI example, which seems to get the CSS in the server-generated step:
Here is my _document.tsx
, which now uses async/await
in getInitialProps
, similar to MUI:
import Document, {
Head,
Html,
Main,
NextScript,
DocumentContext,
} from 'next/document';
import { InjectionMode, resetIds, Stylesheet } from '@fluentui/react';
import * as React from 'react';
/**
* Modified from https://github.com/microsoft/fluentui/wiki/Server-side-rendering-and-browserless-testing#nextjs-setup
* Borrowing render strategy from https://github.com/mui-org/material-ui/blob/master/examples/nextjs/pages/_document.js
*
* Known issue with Fluent UI:
*
* Warning: Prop `className` did not match. Server: "ms-Button-label server-label-6"
* Client: "ms-Button-label label-46"
*/
export default class MyDocument extends Document<{ styleTags: string }> {
static async getInitialProps(ctx: DocumentContext) {
const stylesheet = Stylesheet.getInstance();
stylesheet.setConfig({
injectionMode: InjectionMode.none,
namespace: 'server',
});
stylesheet.reset();
resetIds();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => <App {...props} />,
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styleTags: stylesheet.getRules(true),
};
}
render() {
return (
<Html lang="en">
<Head>
{/* This is fastest. @font-face styles are not necessary. */}
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@200;400;600&display=swap"
rel="stylesheet"
/>
<style
type="text/css"
dangerouslySetInnerHTML={{ __html: this.props.styleTags }}
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
Hope this helps in your efforts to provide solid Next integration with Fluent UI 馃榾
For completeness, here's how my _app.tsx
is set up, including a way to toggle dark mode, something else the docs don't cover very well (I opened a separate issue for that). This feels like the right location for themes.
import { createTheme, Customizer, Fabric } from '@fluentui/react';
import { AppProps } from 'next/app';
import Head from 'next/head';
import React, { createContext, useState } from 'react';
const baseTheme = {
defaultFontStyle: { fontFamily: "'Inter', Helvetica, sans-serif" },
fonts: {
medium: { fontSize: 30 },
},
};
const lightTheme = createTheme({
...baseTheme,
palette: {
},
});
const darkTheme = createTheme({
...baseTheme,
palette: {
themePrimary: 'lightgray',
},
});
export const IsDarkModeContext = createContext<
[boolean, (value: boolean) => void]
>([false, () => {}]);
function MyApp({ Component, pageProps }: AppProps) {
const [isDarkMode, setIsDarkMode] = useState(false);
return (
<>
<Head>
<title>My NextJS App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<IsDarkModeContext.Provider value={[isDarkMode, setIsDarkMode]}>
<Customizer settings={{ theme: isDarkMode ? darkTheme : lightTheme }}>
<Fabric applyTheme>
<Component {...pageProps} />
</Fabric>
</Customizer>
</IsDarkModeContext.Provider>
<style jsx global>
{`
html,
body {
padding: 0;
margin: 0;
font-family: 'Inter', Helvetica, sans-serif;
font-style: normal;
}
* {
box-sizing: border-box;
}
`}
</style>
</>
);
}
export default MyApp;
Tried using @fluentui/react on blitzjs 0.25 (nextjs v10.0.1). Now it works on vanilla blitzjs 0.25 (nextjs v10.0.1) install - without using above hack.
Somehow the warning is changed from classname do not match
into
Warning: Prop `id` did not match. Server: "id__30" Client: "id__3"
at span
at span
at span
at button
Most helpful comment
+1 I am using this with Next.js but having same problem with @NickSevens.