39

I have a web app that I'v designed with material-UI and as you can see below I'm using Button navigation for navigating through my basic landing page components.

<div className="footer">
  <BottomNavigation value={value} onChange={this.handleChange} className={classes.root}>
    <BottomNavigationAction label="signal" value="signal" icon={<ShowChart />} className={classes.content}/>
    <BottomNavigationAction label="hotlist" value="hotlist" icon={<HotList />} className={classes.content}/>
    <BottomNavigationAction label="analyze" value="analyze" icon={<PieChart />} className={classes.content}/>
    <BottomNavigationAction label="learn" value="learn" icon={<LibraryBooks/>} className={classes.content}/>
    <BottomNavigationAction label="dashboard" value="dashboard" icon={<PermIdentity/>} className={classes.content}/>
  </BottomNavigation>
  </div>

I've tried to use React-Router with these predefiend navigation component but that didn't work, is there any possible way to use Router with Button navigation of material-UI? Button navigation article in material-UI ButtonNavigation API

5 Answers 5

75

Yes, it's possible. You need to use the component prop:

import { Link } from 'react-router-dom';

import BottomNavigation from '@material-ui/core/BottomNavigation';
import BottomNavigationAction from '@material-ui/core/BottomNavigationAction';

// ....

<BottomNavigation value={value} onChange={this.handleChange}>
    <BottomNavigationAction
        component={Link}
        to="/signal"
        label="signal"
        value="signal"
        icon={<ShowChart />}
        className={classes.content}
    />
</BottomNavigation>

(the to prop is for React Router's Link component)

This works with any Material-UI component that inherits from ButtonBase.

https://material-ui.com/api/bottom-navigation-action/

Inheritance

The properties of the ButtonBase component are also available. You can take advantage of this behavior to target nested components.

https://material-ui.com/api/button-base/

Props

component - The component used for the root node. Either a string to use a DOM element or a component.

Sign up to request clarification or add additional context in comments.

1 Comment

If you need BottomNavigationAction to be shown as selected when you visit an url, you need to 1. get current location using useLocation from react-router-dom 2. give it to BottomNavigation with value={location.pathname} 3. give each BottomNavigationAction proper value prop, e.g. `value="/about"
10

Just to add on to the great answer by @thirtydot , in case the user types into the search and visits a particular webpage directly (other than default) e.g. "www.yoursite.com/tab2", instead of clicking the 2nd button, this may cause a mismatch between the site that is showing and the BottomNav Button that is focused (usually the 1st button).

Here is what I did:
I used window.location.pathname to get the current path which is '/tab2' directly.
Here is my code for my particular use case....

function BottomNavBar(){
    const pathname = window.location.pathname; // in case user visits the path directly. The BottomNavBar is able to follow suit.
    const [value, setValue] = React.useState(pathname);
    const handleChange = (event, newValue) => {
      setValue(newValue);
    };

    return (
        <BottomNavigation value={value} onChange={handleChange} showLabels={true} >
          <BottomNavigationAction label="home" value="/" icon={<HomeIcon />} component={Link} to='/'/>
          <BottomNavigationAction label="resources" value="/resources" icon={<ResourcesIcon /> } component={Link} to='/resources'/>                
          <BottomNavigationAction label="Q&A" value="/qna" icon={<QnAIcon />}  component={Link} to='/qna'/>
          <BottomNavigationAction label="profile" value="/profile" icon={<ProfileIcon />} component={Link} to='/profile'/>
        </BottomNavigation>
      );
}

3 Comments

Read the answer by @thirtydot first.
@mcKindo No problem! Happy this helped
An add on. Instead of using window.location.pathname (as you have to parse it.. think of the case if the url is '/tab2/123' instead), I believe for CRA users, most likely you will be using react-router-dom. You should use that instead to get the path. import { useLocation } from 'react-router-dom' or refer to this other stackoverflow thread for other alternatives
6

2023 complete answer

Building on @thirdydot's answer and @trashgenerator's comment, filling in all the remaining gaps.

If you want to hook up BottomNavigation with react-router-dom then you want the router to hold the single point of truth. This means to rely on useLocation instead of useState to store this aspect of your app's state and Link to change the state.

There's 3 steps to this:

  1. Make sure you are inside the router context for useLocation to work (see below).
  2. In BottomNavigation set value={useLocation().pathname} instead of useState and onChange.
  3. In BottomNavigationAction use component={Link} and to="/signal" and set the value to that same path.

src/components/RouterBottomNavigation.js

import { useLocation, Link } from 'react-router-dom';
import { BottomNavigation, BottomNavigationAction } from '@mui/material';
/* import icons */

export default function RouterBottomNavigation() {
  return (
    <BottomNavigation
      value={useLocation().pathname}
      className={classes.root}
    >
      <BottomNavigationAction
        component={Link}
        to="/signal"
        value="/signal"
        label="Signal"
        icon={<ShowChart />}
        className={classes.content}
      />
      <BottomNavigationAction
        component={Link}
        to="/dashboard"
        value="/dashboard"
        label="Dashboard"
        icon={<PermIdentity />}
        className={classes.content}
      />
    </BottomNavigation>
  )
}

How does this work? The location pathname now holds the state for your bottom navigation.

If it's /dashboard then your dashboard BottomNavigationAction is active, because it's value is also /dashboard.

And when you click a BottomNavigationAction that is also a router Link, you change the location pathname to the to value.

On being inside the router comntext

And to be inside of the router context, you could place the RouterBottomNavigation next to the Outlet. For example:

src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import Root from "./routes/root";
import Dashboard from "./routes/dashboard";
import Signal from "./routes/signal";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    children: [
      {
        path: "dashboard",
        element: <Dashboard />,
      },
      {
        path: "signal",
        element: <Signal />,
      },
    ]
  },
]);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

src/routes/root.js

import { Outlet } from 'react-router-dom';

import RouterBottomNavigation from "../components/RouterBottomNavigation";

export default function Root() {
  return (
    <>
      <Outlet />
      <RouterBottomNavigation />
    </>
  );
}

Comments

0

in new versions theres this property "LinkComponent" which lets you link directly to a component that renders the page you want, very similar to previus answers:

import { Link } from 'react-router-dom';

import BottomNavigation from '@material-ui/core/BottomNavigation';

import BottomNavigationAction from '@material-ui/core/BottomNavigationAction';

// ....

<div className="footer">
  <BottomNavigation value={value} onChange={this.handleChange} className={classes.root}>
    <BottomNavigationAction label="signal" value="signal" icon={<ShowChart />} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
    <BottomNavigationAction label="hotlist" value="hotlist" icon={<HotList />} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
    <BottomNavigationAction label="analyze" value="analyze" icon={<PieChart />} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
    <BottomNavigationAction label="learn" value="learn" icon={<LibraryBooks/>} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
    <BottomNavigationAction label="dashboard" value="dashboard" icon={<PermIdentity/>} className={classes.content} LinkComponent={Link} to={'/your-route'}/>
  </BottomNavigation>
  </div>
// ...

Comments

0

Whoever is coming here as of September 2023, here is how I got it to work with nextjs link

             <BottomNavigationAction
                aria-label="go home"
                LinkComponent={Link}      // <--- this is next link
                icon={<HomeOutlined />}
                href={'/'} // <---------or build your own href
            />

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.