Search code examples
next.jstailwind-csspostcssjss

Why do tailwind breakpoints not work in this case with Next.js?


I have a component that should hide an element if the viewport is below the md breakpoint. It looks as follows:

function HideUnderBreakpoint({
  breakpoint,
  children,
}: {
  breakpoint: "xs" | "sm" | "md" | "xl";
  children: React.ReactNode;
}) {
  return <div className={`block max-${breakpoint}:hidden`}>{children}</div>;
}

However, when I use this in Next.js, there will be no CSS rules for the class max-something:hidden when inspecting it in the browser.

I have noted that modifying the return value to this generates the class as intended - admittedly ignoring the breakpoint prop:

return <div className={`block max-md:hidden`}>{children}</div>;

But you can now create several of these components and conditionally render the relevant one - and the classes will work as intended.

This seems strange to me, since the breakpoint prop never changes during the lifetime of the component. I would expect Next.js to "just work". I am not certain if the issue is specific to tailwind, postcss, Next.js or even react-jss, which is also present in the project.

Why does this work and the other one does not work?


Solution

  • Tailwind uses regex to find class names, and because of this they need to exist as unbroken strings in your source code. A consequence of this is you cannot use string interpolation the way you're trying to do, as Tailwind will not be able to find the class name.

    What you can do instead is map your props to static class names:

    function HideUnderBreakpoint({
      breakpoint,
      children,
    }: {
      breakpoint: "xs" | "sm" | "md" | "xl";
      children: React.ReactNode;
    }) {
      const sizeVariants = {
        xs: 'max-xs:hidden',
        sm: 'max-sm:hidden',
        md: 'max-md:hidden',
        xl: 'max-xl:hidden',
      }
    
      return <div className={`block ${sizeVariants[breakpoint]}`}>{children}</div>;
    }