2

I am using NextJS with Mantine to develop a site. I have used createStyles to add stylings. Also I try to use as many mantine components as possible.

When I deployed the site on vercel, I found out all site performance parameters were great except CLS, which was terrible; so terrible that you can feel the content shift while starting the site for the first time.

Just for an example, the code for Header is given below:

import { useState } from 'react';
import {
  createStyles, Container, Anchor, Group, ActionIcon, useMantineColorScheme
} from '@mantine/core';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import Sun from '@/public/svg/sun.svg';
import MoonStars from '@/public/svg/moonStars.svg';

const useStyles = createStyles((theme) => ({
  inner: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
  },

  burger: {
    [theme.fn.largerThan('sm')]: {
      display: 'none',
    }
  },

  links: {
    fontWeight: 700,
    textTransform: 'uppercase',
    textDecoration: 'none',
    fontSize: theme.fontSizes.md,
  },

  mainLink: {
    color: theme.colorScheme === 'dark' ? theme.colors.dark[1] : theme.colors.gray[6],
    borderBottom: `2px solid transparent`,
    transition: 'border-color 100ms ease, color 100ms ease',

    '&:hover': {
      color: theme.colorScheme === 'dark' ? theme.white : theme.black,
      textDecoration: 'none',
    },
  },

  mainLinkActive: {
    color: theme.colorScheme === 'dark' ? theme.white : theme.black,
    borderBottomColor: theme.colors[theme.primaryColor][theme.colorScheme === 'dark' ? 5 : 6],
  },

  sideText: {
    color: theme.colorScheme === 'dark' ? theme.white : theme.black,
  }
}));

export default function Component() {
  const { colorScheme, toggleColorScheme } = useMantineColorScheme();
  const { classes, cx } = useStyles();
  let pathname = usePathname();
  const [active, setActive] = useState(() => {
    if (pathname.split('/')[1] === '') return 0;
    if (pathname.split('/')[1] === 'blog') return 1;
  });

  let mainLinks = [
    { "link": "/", "label": "About" },
    { "link": "/blog", "label": "Blog" },
  ]

  const mainItems = mainLinks.map((item, index) => (
    <Anchor component={Link} href={item.link} key={item.label} py='xl' px='md'
      className={cx(classes.mainLink, { [classes.mainLinkActive]: index === active }, classes.links)}
      onClick={() => setActive(index)} >
      {item.label}
    </Anchor>
  ));

  const changeColorScheme = () => {
    toggleColorScheme();
    localStorage.setItem('color-scheme', colorScheme === 'dark' ? 'light' : 'dark');
  }

  return (
    <Container pos='relative' mb='2rem'>
      <Container pos='sticky' className={classes.inner}>
        <div className={classes.links}>
          <Group spacing={0} >
            {mainItems}
          </Group>
        </div>
        <Group position="center" my="xl">
          <ActionIcon
            onClick={() => changeColorScheme()}
            size="lg"
            sx={(theme) => ({
              backgroundColor:
                theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
              color: theme.colorScheme === 'dark' ? theme.colors.yellow[4] : theme.colors.blue[6],
            })}>
            {colorScheme === 'dark' ? <Sun /> : <MoonStars />}
          </ActionIcon>
        </Group>
        {/* <Burger opened={opened} onClick={toggle} className={classes.burger} size="sm" /> */}
      </Container>
    </Container>
  );
}

You can find the website deployed here if you want to try it yourself

One major issue I can think of is that maybe mantine is converting all components into only JS and shipping too much js is making it dynamic and hence all the shifting

If using mantine components is causing the issue, I am ready to shift to native HTML components, but I need to be sure if Mantine's the one causing the issue.

Please help figure out what exactly is causing the high content shift leading to high CLS and how to improve/prevent content shift.

Krushnal Patel
  • 422
  • 2
  • 14
  • Your link doesn't work. – Ethan Jul 16 '23 at 17:30
  • My bad, I updated the link recently and forgot to reflect the changes here. Have updated it now and just in case I missed to update it somewhere else in the questions, its: https://nexvest.vercel.app – Krushnal Patel Jul 16 '23 at 17:51

1 Answers1

2

One major issue I can think of is that maybe mantine is converting all components into only JS and shipping too much js is making it dynamic and hence all the shifting

This is what's wrong. HTML and CSS is always faster than JavaScript. Since your Mantime components depend on JavaScript, your HTML and CSS load first causing a flash of un-styled content.

  1. The best approach would be to switch to native HTML but that would be very difficult.

  2. Another great approach would be to use a headless UI library like Radix UI or Base UI. Most of there components don't require JavaScript and already follow WAI-ARIA accessibility standards. You would still have to manually define your CSS styles.

  3. However, the easist approach would be to create a loading.tsx file in the root of your project to reduce your CLS. Here are the docs for that.

Finally, here's a good article with general tips to reduce CLS.

Ethan
  • 118
  • 1
  • 13