Search code examples
javascriptcssreactjsreact-routerstyled-components

React js app sidebar selected item not highlighted


I created this react app with a side bar, and it looks pretty good, but one thing I can't figure out is how to mark the item (page link) that was clicked.

Here is the code, I added activeClassName="selected" to the SidebarLink const, and added it to the styled-component, but it's not working.

import React, { useState } from "react";
import { Link } from "react-router-dom";
import styled from "styled-components";

const SidebarLink = styled(Link)`
  /*border: 3px solid green;*/
  display: flex;
  color: #e1e9fc;
  justify-content: space-between;
  align-items: center;
  padding: 20px;
  list-style: none;
  height: 60px;
  text-decoration: none;
  font-size: 18px;
  
  &:hover {
    background: #252831;
    border-left: 4px solid #ffbc2e;
    cursor: pointer;
  }

  .selected {
    color: red;
  }
`;
  
const SidebarLabel = styled.span`
  margin-left: 16px;
`;

/* Used for Training dropdown */
const DropdownLink = styled(Link)`
  /*border: 3px solid red;*/
  background: #252831;
  height: 60px;
  padding-left: 3rem;
  display: flex;
  align-items: center;
  text-decoration: none;
  color: #f5f5f5;
  font-size: 16px;
  font-weight: bold;
  
  &:hover {
    background: #48526F;
    border-left: 4px solid #ffbc2e;
    cursor: pointer;
  }
`;

const SubMenu = ({ item }) => {
  const [subnav, setSubnav] = useState(false);
  
  const showSubnav = () => setSubnav(!subnav);
  
  return (
    <>
      <SidebarLink to={item.path} onClick={item.subNav && showSubnav} activeClassName="selected" exact>
        <div className="sidebarTextContainer">
          <div className="sidebarIcon">{item.icon}</div>
          <div className="sidebarText"><SidebarLabel>{item.title}</SidebarLabel></div>
        </div>
        <div>
          {item.subNav && subnav
            ? item.iconOpened
            : item.subNav
            ? item.iconClosed
            : null}
        </div>
      </SidebarLink>
      {subnav &&
        item.subNav.map((item, index) => {
          return (
              <DropdownLink to={item.path} key={index}>
                {item.icon}
                <SidebarLabel>{item.title}</SidebarLabel>
              </DropdownLink>
          );
        })}
    </>
  );
};
  
export default SubMenu;

Anyone got any idea please on how to fix this?


Solution

  • Even though you're asking about remembering which item was clicked, I think what you actually want is that the link corresponding to the current page be highlighted as active.

    If you're using react-router v6, you should use NavLink instead of Link (docs).

    A <NavLink> is a special kind of <Link> that knows whether or not it is "active". By default, an active class is added to a <NavLink> component when it is active.

    You should update the imported component and remove the activeClassName.

    const SidebarLink = styled(NavLink)`
      // ...
      &.active {
        color: red;
      }
    `
    
    // ...
    
    <SidebarLink to={item.path} onClick={item.subNav && showSubnav} exact>
      ...
    </SidebarLink>
    

    If you're using react-router v5, then you should also use NavLink but you have to pass the activeClassName, like you do in your example. In this case you simply need to substitute Link for NavLink.

    Also note that you nested CSS syntax is incorrect. It is applied to the children of SidebarLink, not on SidebarLink itself. You'd want to replace .selected { color: red; } with &.selected { color: red }.