skip to Main Content

I’m getting an error on the className of mapped elements. I believe TS is throwing the error because the map’s children (MenuItem) don’t have the className type. See the error below.

The mapped elements are part of the headlessui package. I think this is part of the reason I’m having trouble. I’m following this introduction to headlessui: https://headlessui.com/react/menu. This example is the third code sample on that page.

I tried to make the MenuItemProps interface to use on the .map function like this:

links.map((link): MenuButtonInterface => ()

How can I include the className type to the children of the .map function?

ERROR:

Type '{ children: Element; key: string; className: string; }' is not assignable to type 'IntrinsicAttributes & CleanProps<ExoticComponent<{ children?: ReactNode; }>, "disabled" | ItemPropsWeControl> & OurProps<...> & { ...; } & { ...; }'.


Property 'className' does not exist on type 'IntrinsicAttributes & CleanProps<ExoticComponent<{ children?: ReactNode; }>, "disabled" | ItemPropsWeControl> & OurProps<...> & { ...; } & { ...; }'.ts(2322)
import React, { ReactNode } from 'react'
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react'

const links = [
    {href: '/home', label: 'Home'},
    {href: '/Test', label: 'Test'},
    {href: '/settings', label: 'Settings'}
]

interface MenuItemProps{
    children: any
    className?: any
    key: any
}

export const MyComponent = () => {
    return(
        <Menu>
            <MenuButton className='data-[active]:bg-blue-500'></MenuButton>
            <MenuItems anchor='bottom'>
                {links.map((link) => (
                    <MenuItem key={link.href} className='block data-[focus]:bg-blue-500'>
                        <a href={link.href}>{link.label}</a>
                    </MenuItem>
                ))}
            </MenuItems>
        </Menu>
    )
}

2

Answers


  1. Use as Prop Directly on MenuItem

    According to the docs you can use the as prop directly in MenuItem to render an a tag and it will allow you to pass the className

    Code will look like this:

    <MenuItem
      key={link.href}
      as="a"
      href={link.href}
      className="block data-[focus]:bg-blue-500"
    
    { link.label }
    </MenuItem>
    

    Hope this helps you.

    Login or Signup to reply.
  2. the issue that I can see is that you are not using the interface "MenuItemProps" that you have created in your component.

    Since you are using Headlessui which already has it’s own types, you can either use

    1. type assertion
    <MenuItem as="div" className="block data-[focus]:bg-blue-500" {...({ key: link.href, children: <a href={link.href}>{link.label}</a>, } as MenuItemProps)} // Type assertion here />
    1. Create a small component, use you interface there and use it in the code
    // Custom component for handling props
    const CustomMenuItem: React.FC < MenuItemProps > = ({
      children,
      className,
      key,
    }) => {
      return ( <
        MenuItem as = "div"
        key = {
          key
        }
        className = {
          className
        } > {
          children
        } <
        /MenuItem>
      );
    };
    
    // Use it in the code
    {
      links.map((link) => ( <
        CustomMenuItem key = {
          link.href
        }
        className = "block data-[focus]:bg-blue-500" >
        <
        a href = {
          link.href
        } > {
          link.label
        } < /a> <
        /CustomMenuItem>
      ))
    }

    **Note: Answer below using

    as Prop

    works fine as well.**

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search