How to add active class on click in react js

Viewed 844

I've read and tried many solutions already, but I'm new to React and I cannot figure out how to add class {s.highlighted} when the div is clicked. Can someone please explain that to me? Here is my code but it's not written by me. I prefer to add {s.highlighted} to "ListItem" when clicked and remove it from the element that was active previously.

It looks like previous developer started doing something but it doesn't work correctly. For now is only 'test-helpers' link always highlighted. What wrong with this code?

const useStyles = makeStyles((theme) =>
  createStyles({
    link: {
      textDecoration: 'none',
      color: theme.palette.grey[900],
    },
    highlighted: {
      backgroundColor: lighten(green[500], 0.5),
    },
  })
)

// eslint-disable-next-line
//@ts-nocheck
export const MenuItems: React.FC = () => {
  const s = useStyles()

  return (
    <div>
      <Link to="/dashboard/proxies" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <CloudDone />
          </ListItemIcon>
          <ListItemText primary="Proxies" />
        </ListItem>
      </Link>

      <Link to="/dashboard/permissions" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <VerifiedUser />
          </ListItemIcon>
          <ListItemText primary="Permissions" />
        </ListItem>
      </Link>

      <Link to="/dashboard/test-helpers" className={classnames(s.link)}>
        <ListItem className={s.highlighted}>
          <ListItemIcon>
            <Help />
          </ListItemIcon>
          <ListItemText primary="Test Helpers" />
        </ListItem>
      </Link>

      <Link to="/dashboard/plans" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <FormatListNumbered />
          </ListItemIcon>
          <ListItemText primary="Plans" />
        </ListItem>
      </Link>

      <Link to="/dashboard/user-management" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <Person />
          </ListItemIcon>
          <ListItemText primary="User Management" />
        </ListItem>
      </Link>

      <Link to="/dashboard/activate-subscription" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <PersonAdd />
          </ListItemIcon>
          <ListItemText primary="Activate Subscription" />
        </ListItem>
      </Link>

      <Link to="/dashboard/user-plan-limits" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <BarChartIcon />
          </ListItemIcon>
          <ListItemText primary="User Plan Limits" />
        </ListItem>
      </Link>
    </div>
  )
}
2 Answers

A naive solution may be something like this. Don't forget to import 'useState' hook from React. You need to keep the track of the active item in the state.

const useStyles = makeStyles((theme) =>
      createStyles({
        link: {
          textDecoration: 'none',
          color: theme.palette.grey[900],
        },
        highlighted: {
          backgroundColor: lighten(green[500], 0.5),
        },
      })
    )
    
    // eslint-disable-next-line
    //@ts-nocheck
    export const MenuItems: React.FC = () => {
      const s = useStyles()
      const [activeItemIndex, setActiveItemIndex] = useState(0)

      return (
        <div>
          <Link to="/dashboard/proxies" className={s.link}>
            <ListItem onClick={() => setActiveItemIndex(0)} className={activeItemIndex === 0 ? s.highlighted : null}>
              <ListItemIcon>
                <CloudDone />
              </ListItemIcon>
              <ListItemText primary="Proxies" />
            </ListItem>
          </Link>
    
          <Link to="/dashboard/permissions" className={s.link}>
            <ListItem onClick={() => setActiveItemIndex(1)} className={activeItemIndex === 1 ? s.highlighted : null}>
              <ListItemIcon>
                <VerifiedUser />
              </ListItemIcon>
              <ListItemText primary="Permissions" />
            </ListItem>
          </Link>
    
          <Link to="/dashboard/test-helpers" className={classnames(s.link)}>
            <ListItem onClick={() => setActiveItemIndex(2)} className={activeItemIndex === 2 ? s.highlighted : null}>
              <ListItemIcon>
                <Help />
              </ListItemIcon>
              <ListItemText primary="Test Helpers" />
            </ListItem>
          </Link>
    
          <Link to="/dashboard/plans" className={s.link}>
            <ListItem onClick={() => setActiveItemIndex(3)} className={activeItemIndex === 3 ? s.highlighted : null}>
              <ListItemIcon>
                <FormatListNumbered />
              </ListItemIcon>
              <ListItemText primary="Plans" />
            </ListItem>
          </Link>
    
          <Link to="/dashboard/user-management" className={s.link}>
            <ListItem onClick={() => setActiveItemIndex(4)} className={activeItemIndex === 4 ? s.highlighted : null}>
              <ListItemIcon>
                <Person />
              </ListItemIcon>
              <ListItemText primary="User Management" />
            </ListItem>
          </Link>
    
          <Link to="/dashboard/activate-subscription" className={s.link}>
            <ListItem onClick={() => setActiveItemIndex(5)} className={activeItemIndex === 5 ? s.highlighted : null}>
              <ListItemIcon>
                <PersonAdd />
              </ListItemIcon>
              <ListItemText primary="Activate Subscription" />
            </ListItem>
          </Link>
    
          <Link to="/dashboard/user-plan-limits" className={s.link}>
            <ListItem onClick={() => setActiveItemIndex(6)} className={activeItemIndex === 6 ? s.highlighted : null}>
              <ListItemIcon>
                <BarChartIcon />
              </ListItemIcon>
              <ListItemText primary="User Plan Limits" />
            </ListItem>
          </Link>
        </div>
      )
    }

You could use the NavLink component of react-router-dom instead, it accepts some props which could allow you to achieve active route behavior, like you are trying to achieve.

Then you could pass s.highlighted to the activeClassName prop and modify the css to target the first child of it which will target the ListItem component.

Here is your updated code:

const useStyles = makeStyles((theme) =>
  createStyles({
    link: {
      textDecoration: 'none',
      color: theme.palette.grey[900],
    },
    highlighted: {
      '& > div': {
        backgroundColor: lighten(green[500], 0.5)
      }
    },
  })
)

// eslint-disable-next-line
//@ts-nocheck
export const MenuItems: React.FC = () => {
  const s = useStyles()

  return (
    <div>
      <NavLink activeClassName={s.highlighted} to="/dashboard/proxies" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <CloudDone />
          </ListItemIcon>
          <ListItemText primary="Proxies" />
        </ListItem>
      </NavLink>

      <NavLink activeClassName={s.highlighted} to="/dashboard/permissions" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <VerifiedUser />
          </ListItemIcon>
          <ListItemText primary="Permissions" />
        </ListItem>
      </NavLink>

      <NavLink activeClassName={s.highlighted} to="/dashboard/test-helpers" className={classnames(s.link)}>
        <ListItem>
          <ListItemIcon>
            <Help />
          </ListItemIcon>
          <ListItemText primary="Test Helpers" />
        </ListItem>
      </NavLink>

      <NavLink activeClassName={s.highlighted} to="/dashboard/plans" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <FormatListNumbered />
          </ListItemIcon>
          <ListItemText primary="Plans" />
        </ListItem>
      </NavLink>

      <NavLink activeClassName={s.highlighted} to="/dashboard/user-management" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <Person />
          </ListItemIcon>
          <ListItemText primary="User Management" />
        </ListItem>
      </NavLink>

      <NavLink activeClassName={s.highlighted} to="/dashboard/activate-subscription" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <PersonAdd />
          </ListItemIcon>
          <ListItemText primary="Activate Subscription" />
        </ListItem>
      </NavLink>

      <NavLink activeClassName={s.highlighted} to="/dashboard/user-plan-limits" className={s.link}>
        <ListItem>
          <ListItemIcon>
            <BarChartIcon />
          </ListItemIcon>
          <ListItemText primary="User Plan Limits" />
        </ListItem>
      </NavLink>
    </div>
  )
}
Related