reactjsnext.jsprimereact

UI elements are displayed shortly with a broken layout before shifting to their intended positions


I am building an application based on React, Next.js and Primereact. I use the app router of Next.js.

When the page is loaded, the UI elements are displayed shortly with a broken layout before shifting to their intended positions.

Shifting from this (wrong) layout: enter image description here

To this (correct) layout: enter image description here

Layout.tsx

import './globals.css';
import 'primereact/resources/themes/saga-blue/theme.css';
import 'primeicons/primeicons.css';
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  );
}

Page.tsx

'use client';

import { Button } from 'primereact/button';
import { Toolbar } from 'primereact/toolbar';
import { SplitButton } from 'primereact/splitbutton';
import { InputText } from 'primereact/inputtext';
import { IconField } from 'primereact/iconfield';
import { InputIcon } from 'primereact/inputicon';
import { Dropdown } from 'primereact/dropdown';
import { useState } from 'react';

export default function Home() {
  const items = [
    {
      label: 'Update',
      icon: 'pi pi-refresh',
    },
    {
      label: 'Delete',
      icon: 'pi pi-times',
    },
  ];

  const startContent = (
    <>
      <Button icon="pi pi-upload" />
    </>
  );

  const centerContent = (
    <IconField iconPosition="left">
      <InputIcon className="pi pi-search" />
      <InputText placeholder="Search" />
    </IconField>
  );

  const endContent = (
    <>
      <SplitButton label="Save" model={items} icon="pi pi-check"></SplitButton>
    </>
  );

  const dropDownOptions = ['value1', 'value2'];
  const [value, setValue] = useState(dropDownOptions[0]);

  return (
    <div className="card">
      <Toolbar start={startContent} center={centerContent} end={endContent} />
      <Dropdown
        options={dropDownOptions}
        onChange={(e) => setValue(e.value)}
        value={value}
      />
    </div>
  );
}

See stackblitz

I also did a screen recording to illustrate the issue.

What is the reason for this and how can I prevent it? I would be really glad if anyone could point me in the right direction.


Solution

  • What you are seeing is a flash of unstyled content because of the Prime styles not being loaded yet. It seems if a Prime React component is added to the JSX markup they load global styles, which are required for styling their UI. This is an open issue at PrimeReact's repo.

    For now you have 2 options:

    1. You can have a loader show up while the styles are being loaded. Playground
    2. Add all styles locally to one CSS file. Playground (This is not foolproof as styles still need to be loaded but here the delay is minimal).

    I would suggest adding a loader.