'MUI Nav Tab with NextJS router - adding icon results in undefined TypeError
I've implemented NavTabs similar to the implementation found here, but using next/router.
Problem: The app crashes if you add an icon to any Tab.
In the Codesandbox, clicking either tab will cause the error. If you then remove the icon property from both Tab components, it will work without issue.
The full code and MUI documentation can be found below.
Additional detail and logging errors:
If you were to use no label and only an icon, like this:
import HomeIcon from '@mui/icons-material/Home'
<LinkTab href="/drafts" icon = {<HomeIcon />} />
Then a click can result in a TypeError thrown at router.push(e.target.href). The same error occurs if you use all three of label, icon, and aria-label.
In the handleTabChange method, I logged the event and found what's changing.
The event from a successful click on a LinkTab with no icon:
SyntheticBaseEvent {_reactName: 'onClick', _targetInst: null, type: 'click', nativeEvent:
PointerEvent, target: a.MuiButtonBase-root.MuiTab-root.MuiTab-textColorPrimary.css-knz1ty-
MuiButtonBase-root-MuiTab-root, …}
The event from an unsuccessful click on a LinkTab with an icon:
SyntheticBaseEvent {_reactName: 'onClick', _targetInst: null, type: 'click', nativeEvent:
PointerEvent, target: path, …}
It seems that the target changes to path sometimes, and as far as I can tell this only happens when an icon is present in the LinkTab.
Any ideas how I can get around this?
Alternative attempt #1:
The below implementation updates the state of the Tabs without crashing, but it won't actually navigate to a new page. If you try to add onClick to the individual Tab components, then the Tabs state won't update as expected.
<Tabs value = {value} onChange = {(e, v) => handleChange(e, v)} aria-label = 'nav'>
<Tab icon = {<HomeIcon />} aria-label = 'home' value = {pages[0]} to = {pages[0]} component = {Link} />
<Tab icon = {<AboutIcon />} aria-label = 'about' value = {pages[1]} to = {pages[1]} component = {Link} />
</Tabs>
Alternative attempt #2:
The below implementation also results in the same TypeError:
import TabContext from '@mui/lab/TabContext'
import TabList from '@mui/lab/TabList'
<TabContext value = {value}>
<TabList value = {value} onChange = {(e, v) => handleChange(e, v)} centered aria-label = 'nav'>
<LinkTab icon = {<HomeIcon />} href = {pages[0]} aria-label = 'home' />
<LinkTab icon = {<InfoIcon />} href = {pages[1]} aria-label = 'about' />
</TabList>
</TabContext>
Error log:
Uncaught TypeError: Cannot read properties of undefined (reading 'auth')
at Object.formatUrl (format-url.js?7b53:32:11)
at Object.formatWithValidation (utils.js?e7ff:109:28)
at resolveHref (router.js?8684:190:69)
at prepareUrlAs (router.js?8684:247:38)
at Router.push (router.js?8684:532:26)
at Object.instance.<computed> [as push] (router.js?31fc:150:20)
at handleTabChange (NavTabs.js?141c:61:12)
at onClick (NavTabs.js?141c:69:25)
at handleClick (Tab.js?4f19:161:1)
...
Full code (also found on Codesandbox):
index.js:
import { useRouter } from "next/router";
import { useState } from "react";
import Box from "@mui/material/Box";
import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import { styled } from "@mui/material/styles";
import HomeIcon from "@mui/icons-material/Home";
import InfoIcon from "@mui/icons-material/Info";
const StyledTab = styled(Tab)(({ theme }) => ({
color: theme.palette.text.primary,
"&:hover": { color: theme.palette.primary.main }
}));
const LinkTab = (props) => {
const router = useRouter();
const handleTabChange = (e) => {
console.log(e);
e.preventDefault();
router.push(e.target.href);
};
return (
<StyledTab
component="a"
disableFocusRipple
disableRipple
onClick={(e) => handleTabChange(e)}
{...props}
/>
);
};
export const NavTabs = () => {
const router = useRouter();
const pages = ["/", "/about"];
const [value, setValue] = useState(pages.indexOf(router.route));
const handleChange = (e, v) => {
setValue(v);
};
return (
<Box>
<Tabs value={value} onChange={(e, v) => handleChange(e, v)} centered>
<LinkTab
label="Home"
href={pages[0]}
icon={<HomeIcon />}
aria-label="home"
/>
<LinkTab
label="About"
href={pages[1]}
icon={<InfoIcon />}
aria-label="about"
/>
</Tabs>
</Box>
);
};
export default () => (
<div>
<NavTabs />
</div>
);
about.js:
import NavTabs from "./index";
export default () => (
<div>
<NavTabs />
</div>
);
MUI documentation:
https://mui.com/components/tabs/#api
https://mui.com/components/tabs/#nav-tabs
https://mui.com/components/tabs/#icon-tabs
https://mui.com/components/tabs/#experimental-api
https://mui.com/components/tabs/#third-party-routing-library
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|

