question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

className did not match between server and client when using useBreakpointValue

See original GitHub issue

Bug report

Describe the bug

Using useBreakpointValue in SSR NextJS project I am receiving in the console:

Warning: Prop `className` did not match. Server: "chakra-heading css-1jlcwm0" Client: "chakra-heading css-2bykvb"

So the issue is I guess, that the Server delivers some style, e.g. for base breakpoint which is different from the actual style on the client, e.g. when it’s a desktop (lg breakpoint) device.

I guess the server would somehow need to deliver the right styles for a device breakpoint. Not sure how that would work, there are some ways to figure out which browser a client uses (e.g. mobile android chrome, etc.) and then assume if its a base, sm, md, lg, xl device.

I am not even sure if thats a bug at all or if that is simply a thing that cannot be fixed due to the nature of server side rendering.

To reproduce

See this example, or check the console in https://codesandbox.io/s/modest-haze-pn9z2?file=/pages/index.js

import { Heading, HeadingProps, useBreakpointValue } from "@chakra-ui/react";

interface DefaultHeadlineProps extends HeadingProps {
  size: "xs" | "s" | "m" | "l";
}
export const DefaultHeadline: React.FC<DefaultHeadlineProps> = ({
  as,
  size,
  children,
  ...props
}) => {
  const headingSizes = {
    xs: { base: "sm", md: "md", lg: "lg", xl: "xl" },
    s: { base: "md", md: "lg", lg: "xl", xl: "2xl" },
    m: { base: "lg", md: "xl", lg: "2xl", xl: "3xl" },
    l: { base: "xl", md: "2xl", lg: "3xl", xl: "4xl" },
  };
  const headingSize = useBreakpointValue(headingSizes[size]);

  const headingMarginBottom = {
    xs: { base: "2", md: "4", lg: "6" },
    s: { base: "4", md: "6", lg: "10" },
    m: { base: "5", md: "7", lg: "12" },
    l: { base: "6", md: "8", lg: "12" },
  };
  const marginBottomSize = useBreakpointValue(headingMarginBottom[size]);

  return (
    <Heading
      as={as}
      fontFamily="Source Sans Pro"
      size={headingSize}
      textTransform="uppercase"
      fontWeight="bold"
      marginBottom={marginBottomSize}
      {...props}
    >
      {children}
    </Heading>
  );
};

Minimal reproduction

https://codesandbox.io/s/modest-haze-pn9z2?file=/pages/index.js

Expected behavior

Generate the same css on server and client.

Additional context

I guess the issue is somewhere here: https://github.com/chakra-ui/chakra-ui/blob/develop/packages/media-query/src/use-breakpoint.ts

The problem is, that we are dependant on the window object which is simply not there on SSR. Is there any way to handle that case for SSR rendered apps?

As a workaround I could just use create different components for my heading sizes like that, which seems to work. Could some1 explain to me why this works? I don’t know if I have the right piece of code here: https://github.com/chakra-ui/chakra-ui/blob/develop/packages/layout/src/heading.tsx

export const HeadlineL: React.FC<HeadingProps> = ({
  as,
  children,
  ...props
}) => {
  return (
    <Heading
      as={as}
      fontSize={{ base: "xl", md: "2xl", lg: "3xl", xl: "4xl" }}
      textTransform="uppercase"
      fontWeight="bold"
      marginBottom={{ base: "6", md: "8", lg: "12" }}
      {...props}
    >
      {children}
    </Heading>
  );
};

Edit: I just noticed, that for that specific case I could also solve the responsive font sizes via theme:

  const extendedTheme = {
    components: {
      Heading: {
        sizes: {
          "6xl": {
            fontSize: { base: "10px", lg: "50px" },
          },
        },
      },
    },
  };

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:5
  • Comments:16 (5 by maintainers)

github_iconTop GitHub Comments

9reactions
pedro-lbcommented, Nov 30, 2020

Here’s a workaround for now (in Typescript, just remove the types if you’re in js):

file: hooks/useBreakpointValue/index.tsx

/* eslint-disable @typescript-eslint/no-explicit-any */

import { useEffect, useRef, useState } from "react";
import { useBreakpointValue as useChakraBreakpointValue } from "@chakra-ui/react";

type Values<T> = (Record<string, T> | T[]) & {
  base: any;
}

/**
 * Hook that exposes the result of Chakra UI `useBreakpointValue` but hydrates the result
 * on the first SSR render.
 *
 * This is done to avoid the "className did not match between server and client" error
 * that happens in `@chakra-ui/react@1.0.1`.
 *
 * Refer to:
 * https://github.com/chakra-ui/chakra-ui/issues/2601
 *
 * TODO: Check if this has been fixed in newer versions and remove this hook.
 *
 * @param values Values as accepted in `useBreakpointValue`.
 */
function useBreakpointValue<T = any>(values: Values<T>): T | undefined {
  const firstRender = useRef(true);
  const [, setTick] = useState(0);

  const result = useChakraBreakpointValue(values);

  /**
   * Force a re-render after the first SSR render and ensures the return value
   * of the hook on next render will be the result of the original hook.
   */
  useEffect(() => {
    if (firstRender.current) {
      setTick((prev) => prev + 1);

      firstRender.current = false;
    }
  }, []);

  if (firstRender.current) {
    return values.base;
  }

  return result;
}

export default useBreakpointValue;
7reactions
velddevcommented, Feb 14, 2022

Hey, I think this needs to be reopened as of @chakra-ui/media-query@1.2.3

Read more comments on GitHub >

github_iconTop Results From Across the Web

Warning: Prop `className` did not match. when using styled ...
It still doesn't work. My issue is that when I reload the page deployed by npm run dev, it throws the error of...
Read more >
useBreakpointValue - Chakra UI
useBreakpointValue is a custom hook which returns the value for the current breakpoint from the provided responsive values object.
Read more >
next js hydration failed - You.com | The search engine you control.
Common issue when you have a mismatch between the server output and the client. Before React 18, you had only get an error...
Read more >
Fixing ClassName did not match error - DEV Community ‍ ‍
Server : Client: This is probably one of the most annoying problem with Next.js, ...
Read more >
@chakra-ui/react Divider JavaScript Examples
The following examples show how to use @chakra-ui/react.Divider. You can vote up the ones you like or vote down the ones you don't...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found