ui icon indicating copy to clipboard operation
ui copied to clipboard

Theme Provider: validateDOMNesting(...): <button> cannot appear as a descendant of <button>.

Open aloksharma10 opened this issue 1 year ago • 10 comments

Hi everyone,

The error message "validateDOMNesting(...):

To reproduce the same error:

  1. Setup dark mode by shadcn/ui
  2. Switch the theme, you'll notice warning is showing into your console.

Warning: image

Code: where the warning is initiating... image

aloksharma10 avatar Feb 16 '24 21:02 aloksharma10

Hi @aloksharma10, the ModeToggle example that you mentioned (it can also be seen here) doesn't nest buttons since the DropdownMenuTrigger has the asChild prop that changes the default rendered element to the one passed as a child.

You most likely forgot to add the asChild prop.

dan5py avatar Feb 17 '24 10:02 dan5py

Hi @aloksharma10, the ModeToggle example that you mentioned (it can also be seen here) doesn't nest buttons since the DropdownMenuTrigger has the asChild prop that changes the default rendered element to the one passed as a child.

You most likely forgot to add the asChild prop.

I appreciate your reply, i already added 'asChild' prop in my codebase as you can see in my issue #2764,

To reproduce the same issue

  1. Create new next app, configure shadcn with your app
  2. Configure Dark Mode with your app, you'll see the same warning in your console

aloksharma10 avatar Feb 17 '24 14:02 aloksharma10

Hi @aloksharma10, I'm considering wrapping lines 26 to 30 into a separate component and then passing children as props from outside. This approach has proven effective for me.

Linlaose avatar Feb 20 '24 03:02 Linlaose

im actually having the same issue, used asChild, this issues just started to come up

hilyas786786 avatar Apr 12 '24 20:04 hilyas786786

 <TooltipProvider delayDuration={0}>
      <Tooltip>
        <TooltipTrigger>
          <TooltipContent className="hidden sm:flex">Theme</TooltipContent>
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button variant="outline" size="icon">
                <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
                <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
                <span className="sr-only">Toggle theme</span>
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end">
              <DropdownMenuItem onClick={() => setTheme('light')}>
                Light
              </DropdownMenuItem>
              <DropdownMenuItem onClick={() => setTheme('dark')}>
                Dark
              </DropdownMenuItem>
              <DropdownMenuItem onClick={() => setTheme('system')}>
                System
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
        </TooltipTrigger>
      </Tooltip>
    </TooltipProvider>

  

hilyas786786 avatar Apr 12 '24 20:04 hilyas786786

The issue seems to be with Tooltip, wherever i use Tooltip i get this issue

hilyas786786 avatar Apr 12 '24 20:04 hilyas786786

same to me

vangetpersona avatar Apr 18 '24 03:04 vangetpersona

The issue seems to be with Tooltip, wherever i use Tooltip i get this issue

I had the same problem with tooltips and when I added asChild to the <TooltipTrigger> tag, the problem went away.

        <TooltipTrigger asChild>
        </TooltipTrigger>

cf-pages avatar Apr 22 '24 05:04 cf-pages

Hello! I'm facing issues with using DropdownMenuTrigger with asChild prop as well.

So, I have this code that works just fine.

<DropdownMenuTrigger asChild>
                <Button
                    variant='outline'
                    className='flex max-lg:p-0 max-lg:w-9'
                >
                    <MixerHorizontalIcon className='lg:mr-2 h-4 w-4' />
                    <span className='max-lg:hidden lg:flex'>View</span>
                </Button>
            </DropdownMenuTrigger>

But when I refactor the Button into another component it doesn't work.

Refactored Button:

type IResponsiveButtonWithIconProps = {
    text?: string;
    icon?: React.FC;
    buttonProps?: React.ComponentPropsWithoutRef<typeof Button>;
    textProps?: React.ComponentPropsWithoutRef<'span'>;
    iconProps?: React.ComponentPropsWithoutRef<'svg'>;
};


export const ResponsiveButtonWithIcon = forwardRef<
    HTMLButtonElement,
    IResponsiveButtonWithIconProps
>(
    (
        {
            buttonProps = {},
            textProps = {},
            text = 'Actions',
            icon: IconComponent = MoreVertical,
            iconProps = {},
        },
        ref
    ) => {
        const {className: buttonClassName, ...restButtonProps} = buttonProps;
        const {className: spanClassName, ...restSpanProps} = textProps;
        const {className: iconClassName, ...restIconProps} = iconProps;

        return (
            <Button
                variant='outline'
                className={cn('flex max-lg:p-0 max-lg:w-9', buttonClassName)}
                {...restButtonProps}
                ref={ref}
            >
                {IconComponent && (
                    <IconComponent
                        className={cn('lg:mr-2 h-4 w-4', iconClassName)}
                        {...restIconProps}
                    />
                )}
                <span
                    className={cn('max-lg:hidden lg:flex', spanClassName)}
                    {...restSpanProps}
                >
                    {text}
                </span>
            </Button>
        );
    }
);

The modified code:

                    <DropdownMenuTrigger /* asChild */>
                        <ResponsiveButtonWithIcon
                            buttonProps={
                                {
                                    // option2: render as something elese
                                    // as: 'div',
                                }
                            }
                            text='Actions'
                            icon={MoreVertical}
                        />

mshahzebraza avatar Apr 26 '24 04:04 mshahzebraza

Using asChild is not fixing the issue for me. I want the tooltip for my buttons

    const MyButton = (
        <Button disabled={disable} className={className} style={style} onClick={onClick} variant="outline">
            {text}
        </Button>
    );
     <TooltipProvider>
                <Tooltip>
                    <TooltipTrigger asChild>{MyButton}</TooltipTrigger>
                    <TooltipContent>
                        <p>{title}</p>
                    </TooltipContent>
                </Tooltip>
            </TooltipProvider>
        

barrard avatar Apr 29 '24 04:04 barrard

This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.

shadcn avatar Jun 11 '24 23:06 shadcn

Still same problem:

I cant nest an dialog in <TooltipTrigger> like this:

<TooltipProvider>
   <Tooltip>
      <TooltipTrigger asChild>
         <Dialog>
            <DialogTrigger asChild>
               <Button variant="outline" size="icon">
                 <Pencil className="h-4 w-4" />
                </Button>    
             </DialogTrigger>
             <DialogContent>
                    <DialogHeader>
                         <DialogTitle>Edit user infos</DialogTitle>
                        <DialogDescription> Change user infos and save changes </DialogDescription>
                    </DialogHeader>
                    <div>
                    </div>
                    <DialogFooter>
                      <DialogClose asChild>
                        <Button type="button" variant="secondary">Close</Button>
                      </DialogClose>
                    </DialogFooter>
                  </DialogContent>
                </Dialog>

                
              </TooltipTrigger>
              <TooltipContent>Miau</TooltipContent>
            </Tooltip>
          </TooltipProvider>

Depending where i set asChild i get the error: Warning: validateDOMNesting(...): <button> cannot appear as a descendant of <button>. or Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

xXTraceXx avatar Jun 12 '24 09:06 xXTraceXx

same issue here, i have the issue DropdownMenuTrigger

mhdizmni avatar Jun 13 '24 20:06 mhdizmni

same issue here, any updates?

wevertoum avatar Aug 22 '24 20:08 wevertoum

Nope, it is still present.

xXTraceXx avatar Aug 30 '24 12:08 xXTraceXx

Still occurring throughout the library.

ZacharyHandshoe avatar Sep 03 '24 00:09 ZacharyHandshoe

This still happens inside the library, confirmed with Tooltip. Why is this issue closed?

churchianity avatar Sep 10 '24 20:09 churchianity

Yup it still happens.

 <TooltipProvider>
      <Tooltip>
        <TooltipTrigger>
          <Badge
            variant={type === "version" ? "outline" : "secondary"}
            className="flex items-center gap-1"
          >
            {Icon && <Icon className="w-3 h-3" />}
            {value}
          </Badge>
        </TooltipTrigger>
        <TooltipContent>{description}</TooltipContent>
      </Tooltip>
    </TooltipProvider>
 

Adding asChild solves that but throws a different warning in my case:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()? simply forwarding ref in badge solved the warning

const Badge = React.forwardRef<HTMLDivElement, BadgeProps>(
 ({ className, variant, ...props }, ref) => {
   return (
     <div
       ref={ref}
       className={cn(badgeVariants({ variant }), className)}
       {...props}
     />
   );
 },
);

Oh god that's why I love shadcn, I can just go in the file and adjust it for my needs ❤️

IhsenBouallegue avatar Sep 14 '24 10:09 IhsenBouallegue