next.jsmaterial-uiparallel-route

How to use parallel routing (of NextJS) with MUI tabs?


We have tabs component of MUI and we have parallel routing of slot. I tried creating this dir structure. But not working properly.

dashboard
├── @tabs
│   ├── approval
│   │   └── page.jsx
│   ├── featured
│   │   ├── loading.jsx
│   │   └── page.jsx
│   ├── notification
│   │   └── page.jsx
│   ├── default.jsx
│   ├── layout.jsx
│   └── page.jsx
├── default.jsx
└── layout.jsx

Solution

  • As we know NextJs supports parallel routing with slot and slot created with dir name @folder/page.jsx

    Directory for dashboard page.

    dashboard
    ├── @tabs
    │   ├── approval
    │   │   └── page.jsx
    │   ├── featured
    │   │   └── page.jsx
    │   ├── notification
    │   │   └── page.jsx
    │   ├── layout.jsx
    │   └── page.jsx
    └── layout.jsx
    

    Dashboard Layout

    dashboard/layout.jsx

    export default function DashboardLayout({ 
      children, 
      tabs 
    }) {
      return (
        <div>
            {tabs} 
        </div>
      )
    }
    

    This file is like Root layout of dashboard page. Optionally you can render children if you want to show common content via dashboard/page.jsx if you render children it will through 404 as we dont have page.jsx or default.jsx file in dashboard/

    Common layout file for all tabs

    dashboard/@tabs/layout.jsx

    'use client';
    import React from 'react';
    import Tabs from '@mui/material/Tabs';
    import Tab from '@mui/material/Tab';
    import { useSelectedLayoutSegment } from 'next/navigation';
    import { useRouter } from 'next/navigation';
    
    const PARENT = 'dashboard';
    const DEFAULT_TAB = 'approval';
    const tabs = [
        { label: 'Approval', value: 'approval' },
        { label: 'Featured', value: 'featured' },
        { label: 'Notification', value: 'notification' }
    ];
    
    export default function TabsLayout({ children }) {
      const currentValue = useSelectedLayoutSegment() || DEFAULT_TAB;
      const router = useRouter();
    
      const handleChange = (event, newValue) => {
        router.push(`/${PARENT}/${newValue}`);
      };
    
    
      return (
        <div>
          <Tabs value={currentValue}  onChange={handleChange} >
            {tabs.map((tab) => (
              <Tab  key={tab.value} label={tab.label}  value={tab.value}  />
            ))}
          </Tabs>
    
          {children} 
    
        </div>
      );
    }
    

    we can make use of useSelectedLayoutSegments method to get current segment of url which will give the last segment of the url. In our example it will be dashboard/[segment] where segment would be featured, approval, notification or null for dashboard/ You can also use MUI's TabPanel, TabContext, TabList etc. Check Doc

    Handle Default tab

    dashboard/@tabs/page.jsx

    import DefaultTabe from "./approval/page";
    export default function(){
        return <DefaultTabe/>
    };
    

    Import any tab component and export from here (@tabs/page.jsx). Because without it url ../dashboard will show nothing and in that case you can only see tab content by clicking on one of tabs first. So the solution fixes this issue.

    You can have loading.jsx, error.jsx, not-found.jsx etc in each tabs dir (i.e. /feature, /approval, /notification) having loading.jsx or default.jsx makes tab switching quicker.

    Result:

    screenshot

    ref:

    1. NextJs - Parallel Routing
      https://nextjs.org/docs/app/building-your-application/routing/parallel-routes
    2. MUI Tabs
      https://mui.com/material-ui/react-tabs/