mui / material-ui

Material UI: Ready-to-use foundational React components, free forever. It includes Material UI, which implements Google's Material Design.
https://mui.com/material-ui/
MIT License
91.86k stars 31.57k forks source link

MUI: The `value` provided to the Tabs component is invalid.... #32749

Closed MatthewMcP closed 2 years ago

MatthewMcP commented 2 years ago

Duplicates

Latest version

Current behavior 😯

When using the tabs component I get,

Tabs.js:366 MUI: The value provided to the Tabs component is invalid. The Tab with this value ("0") is not part of the document layout. Make sure the tab item is present in the document or that it's not display: none.

This occurs both in my own code, and when I copy examples from https://mui.com/material-ui/react-tabs/#experimental-api

There is some stack overflow questions but no solutions https://stackoverflow.com/questions/72085892/mui-the-value-provided-to-the-tabs-component-is-invalid-the-tab-with-this-v https://stackoverflow.com/questions/71613867/mui-nested-tabs-error-the-value-provided-to-the-tabs-component-is-invalid

Expected behavior 🤔

No response

Steps to reproduce 🕹

Steps:

1. 2. 3. 4.

Context 🔦

No response

Your environment 🌎

`npx @mui/envinfo` ``` Don't forget to mention which browser you used. Output from `npx @mui/envinfo` goes here. ```
mnajdova commented 2 years ago

Note that on the example that you linked the <Tab /> components have values: 1, 2 and 3, so if you set value 0 on the <Tabs /> it is indeed expected to see the error, as the value 0 is not used in any <Tab /> inside.

MatthewMcP commented 2 years ago

So below is my exact code. I assume the enum is converting to being a number but I'm still getting the above error

    enum SelectedTab {
        DepartmentSharesTab,
        DelegatedTab,
        PersonalTab,
        ReportingTab
    }
    const [selectedTab, setSelectedTab] = useState(SelectedTab.DepartmentSharesTab);
        <Tabs
                value={selectedTab}
                onChange={(e, value) => {
                    setSelectedTab(value);
                }}>
                <Tab value={SelectedTab.DepartmentSharesTab} label='Department Shares View' />
                <Tab value={SelectedTab.DelegatedTab} label='Delegated View' />
                <Tab value={SelectedTab.PersonalTab} label='Personal View' />
                <Tab value={SelectedTab.ReportingTab} label='Reporting' />
            </Tabs>

            <Box m={4}>
                {selectedTab === SelectedTab.DepartmentSharesTab && <DepartmentShares />}
                {selectedTab === SelectedTab.DelegatedTab && <div> Delegated</div>}
                {selectedTab === SelectedTab.PersonalTab && <div> Personal</div>}
                {selectedTab === SelectedTab.ReportingTab && <div> Reporting</div>}
            </Box>
lalLAL95828 commented 1 year ago

this is a bug

MatthewMcP commented 1 year ago

Is this a bug with my code or a MUI? If it's MUI is there somewhere better to follow this?

ghost commented 1 year ago

any updates?

samislam commented 1 year ago

I encountered this bug 4 months ago and now it's happening again even after the latest updates.

nadeeshaDileen commented 1 year ago

Any solution?

mati-1 commented 1 year ago

you need to: <Tabs ---> value={false} <--- />

kiko-lin commented 1 year ago

you need to: <Tabs ---> value={false} <--- />

Yes Sir! You are right. In fact, for me the problem came from

const [value, setValue] = useState(0) <Tabs ---> value={value}

If you do so the error appears. Guess TabPanel is not already created or recognized on first render but ...

const [value, setValue] = useState(false) useEffect stating initial 0 or any other tabPanel id value <Tabs ---> value={value}

works like a charm as 0 should point to a tabpanel id but false means no id value at all.

Thank you very much @skrimusss

rpggio commented 1 year ago

I encountered this on page load when a suspended component was rendering next to the tabs. Putting <Suspense> around the suspended element made the tabs error go away.

samislam commented 1 year ago

you need to: <Tabs ---> value={false} <--- />

Yes Sir! You are right. In fact, for me the problem came from

const [value, setValue] = useState(0) <Tabs ---> value={value}

If you do so the error appears. Guess TabPanel is not already created or recognized on first render but ...

const [value, setValue] = useState(false) useEffect stating initial 0 or any other tabPanel id value <Tabs ---> value={value}

works like a charm as 0 should point to a tabpanel id but false means no id value at all.

Thank you very much @skrimusss

For some reason I am getting

react_devtools_backend.js:4026 Warning: Failed prop type: Invalid prop `value` of type `boolean` supplied to `ForwardRef(TabPanel)`, expected `string`.
samislam commented 1 year ago

I have tried everything, approximately 46 hours trying to figure out a workaround for this error. But no-way. It's obviously a bug. And it has to be fixed. And for the people who were able to find some workarounds for their projects. Congratulations. But for me, I'll have to wait for the next update until one of the maintainers commit a patch release for this particular bug, which is the only one I was able to catch during my project which I was working on (for 9 months). Mui is a great library. And this is the only bug I was able to find in "@mui/material". Some other bugs I encountered in "@mui/x-data-grid". But let's forget about that now.

I was able to complete my entire project peacefully, the only part left for me is this error. But it's okay for now, the project still can survive with that.

image image image image

CoNETProject commented 1 year ago

Same as me.

sera-1994 commented 1 year ago

Same as me

AlexOla-NG commented 1 year ago

Same here.

I have the exact same problem as @samislam

17x commented 1 year ago

same here

nhd2106 commented 1 year ago

same here

suren-atoyan commented 1 year ago

+1

SEHEE019 commented 1 year ago

Same as me......

Dodge164 commented 1 year ago

+1

joaottc commented 1 year ago

same thing here

maria-mcparland commented 1 year ago

+1

kiko-lin commented 1 year ago

@samislam I realize that you are using labs components. I am not. Maybe this is something to check.

brightmileDaniel commented 1 year ago

+1

asrinutku commented 1 year ago

+1

guptaShyam123 commented 1 year ago

i previously added display:none in sm device then i removed this , now its working properly

PawelNackiewicz commented 1 year ago

+1

Ediste commented 1 year ago

Please reopen the issue its still a problem.

ghost commented 1 year ago

+1

hongdeyuan commented 1 year ago

+1

infinite4evr commented 1 year ago

+1

hongdeyuan commented 1 year ago

本人已收到您的邮件,辛苦了!如有重要事情,看到后,将尽快给你回复。。。

infinite4evr commented 1 year ago

@mnajdova Please re-open this issue

beebeebeeebeee commented 1 year ago

+1

devleesch001 commented 1 year ago

+1

gretencord commented 1 year ago

I encountered this on page load when a suspended component was rendering next to the tabs. Putting <Suspense> around the suspended element made the tabs error go away.

Similar circumstance although in my case the suspended element was a child of the first visible tab panel.

ITpandaffm commented 1 year ago

+1

Lucas-Je commented 1 year ago

const [value, setValue] = useState(false);

useEffect(() => { setTimeout(() => { setValue(0); }, 100); }, []);

mnajdova commented 1 year ago

I can re-open it if someone shares a sandbox with a reproduction. I've responded what is the problem with the initially created sandbox. Adding a "+1" and "same here" is not helpful without a reproduction that we can look into.

samislam commented 1 year ago

Hey friends, I have tried to make a stack blitz instance to re-produce the problem, but I couldn't, (don't say I want the problem to happen, of course not).

The test shows no errors at all, I have tried to use react-router-dom with <Outlet /> to make twice sure it's not the source of the problem, and it looks like it's not.

I wasn't able to reproduce the problem, so everyone, please fork this project, and try to cause the error message to show up:

Sandbox (Stack Blitz): Click me Sandbox (Live preview): Click me

mracette commented 1 year ago

I think the issue here is that MUI checks if the immediate children have a value prop regardless of whether or not they are Tab components. @mnajdova here's a reproduction that shows the issue: https://codesandbox.io/s/mui-tab-error-repro-ibq0iz?file=/src/App.tsx

Whether or not this is a bug, I'm not sure. But it does seem like this use case should be supported.

rossipedia commented 1 year ago

Hi, I think I have a reproduction here, at least for the edge-case that I'm running into.

It seems to happen when the component that is rendering the <Tabs /> component suspends. React seems to be setting the element, or a parent, to display: none1, which means that when <Tabs /> tries to get the bounding rect, it comes back as 0 for height and width. This triggers the error message2.

Here's my sample repo that shows the error:

https://github.com/rossipedia/mui-tabs-invalid-value-repro


1: I think this is an optimization on React's part for Suspended trees, since I would've assumed that the children of a Suspense component that has been suspended would've been unmounted and the DOM cleaned up.

2: Relevant MUI source: https://github.com/mui/material-ui/blob/2093d62046a1fd1342d0e5e6ef7f156faf778b52/packages/mui-material/src/Tabs/Tabs.js#L361-L371

Alena-Levina commented 1 year ago

I have faced this issue in my React app with Ionic.

The issue appears because initially selected tab button has width = 0 and height = 0 (for ex. because of display: none or for any other reason)

It turned out that in my case MUI Tabs were trying to render before Ionic page loaded completely which made selected tab button having width = 0 and height = 0 (but it was present in the DOM).

This MUI tabs code was triggering this error: https://github.com/mui/material-ui/blob/2093d62046a1fd1342d0e5e6ef7f156faf778b52/packages/mui-material/src/Tabs/Tabs.js#L357-L374 And what was failing for me is width / height zero check.

I have found 2 workarounds to fix this issue in my case:

1) Use false as initial Tabs value and set actual value in useEffect -> setTimeout: This workaround might be helpful to anyone who faces this console error.

// code of React component that uses MUI <Tabs> component

const [tabsValue, setTabsValue] = useState(false);

useEffect(() => {
    setTimeout(() => {
        setTabsValue(actualValue);
    }, 0) // 0 ms  was enough for my case :) Just useEffect alone didn't work
}, []);

return (
    <Tabs value={tabsValue}>
        ....
    </Tabs>
)

I did not particularly liked this solution because I don't like using setTimeouts to fix issues like that since it does not seem too reliable

2) Use Ionic's useIonViewDidEnter lifecycle hook This workaround might be helpful for those who face this console error with Ionic

import { useIonViewDidEnter } from '@ionic/react';

// code of React component that uses MUI <Tabs> component

const [tabsValue, setTabsValue] = useState(false);

useIonViewDidEnter(() => {
     setTabsValue(actualValue);
});

return (
    <Tabs value={tabsValue}>
        ....
    </Tabs>
)

I preferred this workaround as it seems to be more reliable as it reacts only when selected tab button is fully rendered.


I still have a question to devs of MUI Tabs - why do you need this width / height check here? https://github.com/mui/material-ui/blob/2093d62046a1fd1342d0e5e6ef7f156faf778b52/packages/mui-material/src/Tabs/Tabs.js#L357-L374

It is not obvious it is a requirement, as well as it seems to create problems for any kind of lazy loading or hidden elements and etc. which I don't think it was supposed to.

@mnajdova , as you are the one who closed the issue, could you clarify why should an error be shown when selected tab button has zero width / height?

mnajdova commented 1 year ago

I think the issue here is that MUI checks if the immediate children have a value prop regardless of whether or not they are Tab components. @mnajdova here's a reproduction that shows the issue: https://codesandbox.io/s/mui-tab-error-repro-ibq0iz?file=/src/App.tsx

Whether or not this is a bug, I'm not sure. But it does seem like this use case should be supported.

@mracette the Tabs component uses React.cloneElement for appending some props to the children elements. If you are not using the Tab component there, you need to spread the props to the appropriate component (in your case, the MyTab should spread all props to the Tab element.

@rossipedia @Alena-Levina can you please create separate issues? Although the error shown is the same, it seems to be related to different topics. @Alena-Levina it would help if you could share sandbox/repository with minimal reproduction on the new issue. From what I can see, it may be related to https://github.com/mui/material-ui/issues/33606 (the whole tabs are not visible, so the error shouldn't be shown at all).

@rossipedia @Alena-Levina would be great if you can check if https://github.com/mui/material-ui/pull/34026#pullrequestreview-1233714371 fixes the issues you have. You can use the build packages from the PR: https://pkg.csb.dev/mui/material-ui/commit/6336475f/@mui/material. See instructions about local installation here: https://ci.codesandbox.io/status/mui/material-ui/pr/34026/builds/331163

tiavina-mika commented 1 year ago

+1

shams-shimul commented 1 year ago

I have been wrestling with this problem for about a month now in a project that was started a few months ago with MUI v5.10.9 and I have tried every trick that I could scrape off the Internet (not many though), but nothing worked for me until I upgraded to v5.11.4 just moments ago and that ugly console error is no more there! 🤩 Hurray! Probably they have fixed it in recent updates. Sheesh! It has been driving me nuts for the last month. Tons of thanks to the MUI guys 👍 for fixing this and allowing my subconscious to have some peace finally 😮‍💨

So, folks, just upgrade your MUI dependency version.

airfortech commented 1 year ago

I have handled it. The solution is providing to Tabs actually available links. In my case after refresh page only "/" route is available then code is checking if user is logged. When he is, available tabs increase. That was the main problem, when i was refreshing page "/other_route", this route wasnt available before status was checked. But I was providing all links not only available at the moment.

import { useLocation } from "react-router-dom";

export const useRouteMatch = (patterns: string[]) => {
  const { pathname } = useLocation();

  if (pathname === "/") return "/";
  const path = "/" + pathname.split("/")[1];
  if (patterns.includes(path)) return path;
  return false;
};
export const Navigation = () => {
  const { auth } = useAuth();

  const availableLinks = links.filter(({ allowedRoles }) =>
    isRoleAllowed(allowedRoles, auth?.role)
  );
  const currentTab = useRouteMatch(availableLinks.map(({ url }) => url));

  return (
    <nav className={classes.Navigation}>
      <Tabs
        value={currentTab}
        variant="scrollable"
        scrollButtons="auto"
        allowScrollButtonsMobile
        selectionFollowsFocus
        className={classes.tabs}
      >
        {availableLinks.map(({ url, name, icon, allowedRoles }) => (
          <Tab
            value={url}
            key={name}
            label={name}
            icon={icon}
            iconPosition="start"
            component={Link}
            to={url}
          />
        ))}
      </Tabs>
    </nav>
  );
};
fuyan-run commented 8 months ago

<Tabs value={value || false} ...

orassyag commented 5 months ago

Still have this issue, and if I add <Tabs value={value || false} i can't see the selected tab on the tabs menu.

timur-rgm commented 4 months ago

I had the same error when displayed tabs only on mobile. I just exported useMediaQuery and used it for conditional render:

import { useMediaQuery } from '@mui/material'

// ...

const isMobile = useMediaQuery('(max-width: 768px)')

if (!isMobile) return null

return (
  <TabContext value={value}>
    // ...
  </TabContext>
)

I don't think this is a good solution, but it helped me so far