primereact icon indicating copy to clipboard operation
primereact copied to clipboard

Flash of unstyled content (FOUC)

Open gslopez opened this issue 1 year ago • 25 comments

Describe the bug

When using built in PR theme seeing a flash of un-styled content: https://en.wikipedia.org/wiki/Flash_of_unstyled_content

I have this super simple code

import React, {useState} from 'react';
import {TabMenu} from 'primereact/tabmenu';
import {MenuItem} from 'primereact/menuitem';


type NavbarProps = {
    onPageSelected?: (page: string) => void,
    menuItems?: MenuItem[],
}

export const Navbar = ({menuItems, onPageSelected}: NavbarProps) => {
    const [activeIndex, setActiveIndex] = useState(0)

    return (
        <TabMenu
            activeIndex={activeIndex}
            model={
                menuItems
            }
            onTabChange={(e) => {
                setActiveIndex(e.index);
                onPageSelected?.(e.value.id as string)
            }}
        />
    )
}

When the page first loads, it looks like this first for like 0.5 seconds

Screenshot 2023-10-29 at 3 24 56 PM

and then it changes to how it should really look

Screenshot 2023-10-29 at 3 24 47 PM

After some debugging I found out it is because when the component is loaded, it loads this global style Screenshot 2023-10-29 at 3 27 42 PM

https://github.com/primefaces/primereact/blob/master/components/lib/tabmenu/TabMenuBase.js#L79 https://github.com/primefaces/primereact/blob/master/components/lib/componentbase/ComponentBase.js#L664

I recorded this video with the issue on the codesandbox i created

https://github.com/primefaces/primereact/assets/2165906/01eb40c2-e062-40ee-8934-3355b858f502

I would expect either

  1. The component should be auto-sufficient (i.e it looks properly on first load)
  2. To have a way to import the components css globally directly, next to the theme and min imports (something like import "primereact/components/tabmenu.css

Reproducer

https://codesandbox.io/s/primereact-test-forked-xsr6gj?file=/src/index.js

PrimeReact version

10.0.7

React version

18.x

Language

TypeScript

Build / Runtime

Create React App (CRA)

Browser(s)

No response

Steps to reproduce the behavior

No response

Expected behavior

No response

gslopez avatar Oct 29 '23 22:10 gslopez

I agree I have seen this same flash flicker when it renders.

This is known as FOUC https://en.wikipedia.org/wiki/Flash_of_unstyled_content and maybe all those base styles need to be extracted into a primereact.css like you said so if we want we can include it in the page and not need each component to dynamically add the CSS to the HEAD

melloware avatar Oct 30 '23 11:10 melloware

@gslopez check this out can you try this: https://codesandbox.io/s/primereact-test-forked-9cl6y8?file=/src/styles.css

I merged all of the base styles into a single CSS file to load. If this meets your needs I think I can propose something clever.

melloware avatar Nov 02 '23 19:11 melloware

Updated with more complete version of the final CSS: https://codesandbox.io/s/primereact-test-forked-9cl6y8?file=/src/styles.css

melloware avatar Nov 03 '23 13:11 melloware

hey @melloware! Thanks for the quick answer. Yeah, if I add import "./styles.css"; to that codesandbox it seems to be working fine. I think this is good enough for my current project 🙏

gslopez avatar Nov 03 '23 17:11 gslopez

@melloware any date prediction of 10.0.10 release? Facing the same issue here

alaordev avatar Nov 09 '23 05:11 alaordev

This fix has not been included in 10.0.10 yet as PrimeTek is still discussing my fix. For now you can use the CSS in the reproducer above to temporarily fix your issue.

melloware avatar Nov 09 '23 14:11 melloware

NextJS 14 reproducer: https://stackblitz.com/edit/stackblitz-starters-mqapwn?file=app%2Fglobals.css,app%2Flayout.tsx

melloware avatar Nov 21 '23 14:11 melloware

Facing the same issue while migrating to a major version 8 → 10 on my project. Any news here? It's look like a blocker for me

axlerk avatar Feb 01 '24 23:02 axlerk

You can use my workaround posted above

melloware avatar Feb 02 '24 00:02 melloware

You can use my workaround posted above

@melloware do you mean this?

Updated with more complete version of the final CSS: https://codesandbox.io/s/primereact-test-forked-9cl6y8?file=/src/styles.css

This codesandbox still shows a FOUC on first load. It's a little less noticeable but it still occurs. A little difficult to show with Chrome Inspector (it limits how big the Visual Preview window can be) but the following shows the list elements along with the final rendered content 1ms later:

image image

lsegal avatar Feb 04 '24 00:02 lsegal

Yes it doesn't eliminate it it just makes it less jarring by preloading CSS.

melloware avatar Feb 04 '24 00:02 melloware

Is it possible to somehow escalate this issue? Add more likes or idk :) Looks important.

axlerk avatar Mar 19 '24 15:03 axlerk

@axlerk PrimeTek is aware of this issue its on their radar.

melloware avatar Mar 19 '24 15:03 melloware

any news?

emirhancopoglu avatar May 09 '24 17:05 emirhancopoglu

any news?

+1

thingersoft avatar May 10 '24 00:05 thingersoft

+another

cdllc avatar May 19 '24 00:05 cdllc

+++

emirhancopoglu avatar May 21 '24 20:05 emirhancopoglu

++++

starlocater avatar Jun 03 '24 07:06 starlocater

@melloware could you update the workaround for version 10.6.6 please? Until we have a solution

axlerk avatar Jun 03 '24 14:06 axlerk

@axlerk i assume you means some styles are missing from my giant CSS file?

melloware avatar Jun 03 '24 14:06 melloware

Now I get what @melloware is saying now, PrimeReact adds the styles 'after' the component have already been rendered. See the left side of the screenshot and you'll notice that 'base', 'global', 'splitbutton', are being added dynamically. On the right side of the screen, you don't and that's why it's showing FOUC.

image

I think I can come with decent 'workaround' solution without putting those css somewhere. My idea is the following. Please let me know if my logic can be improved or flawed.

  1. Make the body tag to be display:none in the Root Layout component. Something like
<body style={{display: "none"}}>
  1. Add a script tag, that checks for added styles with the attribute 'data-primereact-style-id'. Check that at least 3 of them exists (Imagine those are 'base', 'global', 'common') and maybe add another 50ms and then change the body style back to 'block'/'flex'/or whatever...

Hopefully this will work as temporary workaround...

acho1833 avatar Jun 08 '24 03:06 acho1833

@acho1833 yes you understand the issue now. PrimeTek I think is working on a long term solution after their next big refactor.

melloware avatar Jun 08 '24 10:06 melloware

My theory seems to work and I think it's good to go now. To me, this is enough until the fix and looks perfect to me.


export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <head>
        <style
          dangerouslySetInnerHTML={{
            __html: `
              body {
                display: none;
              }
            `,
          }}
        />
        <script
          dangerouslySetInnerHTML={{
            __html: `
                document.addEventListener('DOMContentLoaded', function() {
                    const intervalId = setInterval(() => {
                        const elements = document.querySelectorAll('head > style[data-primereact-style-id]');
                        if (elements.length >= 3) {
                            document.body.style.display = 'block';
                            clearInterval(intervalId);
                        }
                    }, 50);
                });
            `,
          }}
        />
      </head>
      <body className={inter.className}>
        <PrimeReactProvider>{children}</PrimeReactProvider>
      </body>
    </html>
  );
}

@melloware looking forward for next release. Is that real soon? know any rough ETA?

acho1833 avatar Jun 08 '24 12:06 acho1833

I don't work for PrimeTek so I don't know the internal details of their schedule or roadmap.

melloware avatar Jun 09 '24 11:06 melloware