Tailwind-Styled-Component icon indicating copy to clipboard operation
Tailwind-Styled-Component copied to clipboard

TypeError: l is not an function

Open SpencerIsTheKey opened this issue 7 months ago • 1 comments

I recently started a new personal project and decided to take the opportunity to learn Tailwind CSS after working with vanilla CSS for a while. I quickly found that it I was having to scroll horizontally to see all of my styles, and found that this library made my life much easier.

I then built the following components with it to create my navigation bar:

NavItem.tsx:

import tw from "tailwind-styled-components";
import { FunctionComponent } from "react";


type Props = {
    text: string;
    href: string;
    active: boolean;
}

const NavItem: FunctionComponent<Props> = ({ text, href, active}) => {

    const NavLink = tw.link`
        text-base
        relative
        transition-all
        duration-200
        md:flex-row
        md:w-fit
        md:gap-24
        md:items-center
        md:before:absolute
        md:before:w-0
        md:before:h-6
        md:before:-bottom-16
        md:before:left-0
        md:before:bg-black
        md:before:transition-all
        md:before:duration-200
        hover:font-bold
        ${active ? "font-bold": "" }
    `;
    return(
        <NavLink href={href}>
            {text}
        </NavLink>
    );
}
export default NavItem;

NavBar.tsx:

import Link from "next/link";
import { useState } from "react";
import tw from "tailwind-styled-components";
import NavItem from "./NavItem";


const MENU_LIST = [
  {text: "Home", href:"/"},
  {text: "About", href: "/about"},
  {text: "Contact", href: "/contact"},
  {text: "Account", href: "/account"}
];

const NavBar = () => {
  const [navActive, setNavActive] = useState(false);
  const [activeIdx, setActiveIdx] = useState(-1);


  const NavBarWrapper = tw.nav`
    flex
    h-20
    p-16
    justify-between
    items-center
    bg-primary
    sticky
  `;
  const NavBurger = tw.div`
    flex-col
    gap-6
    md:hidden
  `;
  const NavBurgerLayer = tw.div`
    w-40
    h-4
    bg-black
    rounded-sm
  `;
  const NavList = tw.div`
    flex-col
    fixed
    top-60
    w-56
    gap-24
    -right-56
    py-24
    px-16
    transition-all
    duration-200
    ${navActive ? "right-0" : ""}
  `;
  return(
    <>
    <header>
      <NavBarWrapper>
        <Link href="/" onClick={() => setActiveIdx(0)}>
            <h1>TEMP LOGO</h1>
        </Link>
        <NavBurger
          onClick={() => setNavActive(!navActive)}
        >
          <NavBurgerLayer/>
          <NavBurgerLayer/>
          <NavBurgerLayer/>
        </NavBurger>

        <NavList>
          {MENU_LIST.map((menu, idx) => (
            <div onClick={() => {
              setActiveIdx(idx);
              setNavActive(false);
            }}
            key={menu.text}
            >
              <NavItem active={activeIdx === idx} {...menu} />
            </div>
          ))}
        </NavList>
      </NavBarWrapper>
    </header>
    </>
  )
}

export default NavBar;

Once I added this to my layout, a runtime error occurred that was labelled TypeError: l is not a function, with the trace showing an origin inside a tailwind-styled-components file. Two function calls into tailwind-styled-components, in fact

I've checked through all of my Tailwind classes to make sure that I'm not trying to use an invalid class, and the only thing I found that might have been complicating things was the md:before: classes. I split the styled class to remove those modifiers like so:

import tw from "tailwind-styled-components";
import { FunctionComponent } from "react";
import Link from "next/link";


type Props = {
    text: string;
    href: string;
    active: boolean;
}

const NavItem: FunctionComponent<Props> = ({ text, href, active}) => {

    const NavLinkWrapper = tw.div`
        text-base
        relative
        transition-all
        duration-200
        hover:font-bold
        md:flex-row
        md:w-fit
        md:gap-24
        md:items-center
        ${active ? "font-bold": "" }
    `
    const NavAnimation = tw.div`
        hidden
        md:absolute
        md:w-0
        md:h-6
        md:-bottom-16
        md:left-0
        md:bg-black
        md:transition-all
        md:duration-200
    `
    return(
        <NavLinkWrapper>
            <Link href={href} >
                {text}
            </Link>
            <NavAnimation />
        </NavLinkWrapper>
        
    );
}
export default NavItem;

But found no difference. I then removed the Tailwind classes from the styled components and applied them to regular HTML elements and found the issue to be resolved. I would really love to be able to use this for my project, but as it stands now it seems to simply not work

SpencerIsTheKey avatar Dec 30 '23 12:12 SpencerIsTheKey

I also had this same problem, when passing a prop "directly" to the component, in your case the prop "active":

    const NavLinkWrapper = tw.div`
        text-base
        relative
        transition-all
        duration-200
        hover:font-bold
        md:flex-row
        md:w-fit
        md:gap-24
        md:items-center
        ${active ? "font-bold": "" }
    `

Try passing it like this:

        <NavLinkWrapper active={active}>
            <Link href={href} >
                {text}
            </Link>
            <NavAnimation />
        </NavLinkWrapper>

🇧🇷 Tradução: Pra quem teve o mesmo erro (igual a mim), provávelmente é porque a prop "active" está sendo passada diretamente para o comoponente criado com tw (primeiro exemplo), basta passar a prop para o componente como o segundo exemplo.

Yuji-Guilherme avatar Mar 07 '24 04:03 Yuji-Guilherme