Home > Software design >  How can I create a dynamic class toggler for a sidebar in React?
How can I create a dynamic class toggler for a sidebar in React?

Time:04-07

So I want to assign a class to a clicked link within a sidebar to assign a specific class. This works for one Link in the sidebar, but once I attach the handler to another Link element and click it both Link elements are assigned with the new class.

How can I make this more like a toggler so only one Link element "is clicked" at a time? Is there some sort of self to refer only to the clicked element?

import {useState} from "react";
import {Routes, Route, Link } from "react-router-dom";

import PlannerWrapper from "./PlannerWrapper"

const DashboardWrapper = () => {

    // Class Toggler for clicked element
    const [isClicked, setIsClicked] = useState(false)
    const clickedClass = 'link-item flex items-center mb-4 rounded-md p-2 pl-4 shadow-lg bg-sx-purple text-sx-pink';

    const clickHandler = () => {
        setIsClicked(true)
    }

    return (
        <div className="body-wrapper w-full h-screen flex">
            <div className="sidebar w-1/6 2xl:w-1/8 h-full bg-sx-purple-dark-soft p-4 border-r-sx-pink border-r-2">
                <div className="sidebar-body p-4">
                    <div className="link-wrapper">
                        <Link to="/dashboard/overview/">
                            <div className={isClicked && `${clickedClass}`} onClick={clickHandler}>
                                <img className="link-icon flex w-4 mr-4" src={imageLocation} alt="imageIcon"/>
                                <div className="link-text">Overview</div>
                            </div>
                        </Link>
                        <Link to="/dashboard/planner/">
                            <div className={isClicked && `${clickedClass}`} onClick={clickHandler}>
                                <img className="link-icon flex w-4 mr-4" src={imagePlanner} alt="imageIcon"/>
                                <div className="link-text ">Planner</div>
                            </div>
                        </Link>
                   </div>
               </div>
           </div>
...

CodePudding user response:

I can think of two approaches

1 manually add a tag to each element

const [clicked, setClicked] = useState('')

and on your link element

    <Link to="/dashboard/overview/">
      <div className={clicked === 'overview' && `${clickedClass}`} onClick={() => setClicked('overview')}>
      <img className="link-icon flex w-4 mr-4" src={imageLocation} alt="imageIcon"/>
   <div className="link-text">Overview</div>
   </div>
</Link>

2 render nav with map and an array like this

const navs = [
  {
   link: '/dashboard/overview/',
   image: imageLocation,
   label: 'Overview'
},  {
   link: '/dashboard/planner/',
   image: imagePlanner,
   label: 'Planner'
}, 
]

and then

<div className="body-wrapper w-full h-screen flex">
            <div className="sidebar w-1/6 2xl:w-1/8 h-full bg-sx-purple-dark-soft p-4 border-r-sx-pink border-r-2">
                <div className="sidebar-body p-4">
                    <div className="link-wrapper">
                        {navs.map(({link, image, label}, i) => 
                          
                        <Link to={link} key={i}>
                            <div className={clicked === i && `${clickedClass}`} onClick={() => setClicked(i)}>
                                <img className="link-icon flex w-4 mr-4" src={image} alt="imageIcon"/>
                                <div className="link-text ">{label}</div>
                            </div>
                        </Link>
                          )}
                   </div>
               </div>
           </div>


CodePudding user response:

If you only have two links then create two states and assign boolean to that onClick and check. In clickHandler when user select 1st link assign true to it and false to second and when user selects second link then assign false to first and true to second.

If you have more than 2 links: Take 1 : set something (like id,name) in an state of array where you can check that user has clicked on this link and show the particluar css to all those links which are clicked.

Take 2: Update your clickHandler with setIsClicked(!isClicked)

UPDATE:

    import {useState} from "react";
    import {Routes, Route, Link } from "react-router-dom";
    
    import PlannerWrapper from "./PlannerWrapper"
    
    const DashboardWrapper = () => {
    
        // Class Toggler for clicked element
        const [isClicked, setIsClicked] = useState<number[]>([])
        const clickedClass = 'link-item flex items-center mb-4 rounded-md p-2 pl-4 shadow-lg bg-sx-purple text-sx-pink';
    
        const clickHandler = (id:number) => {
  const tempIsClicked = [...isClicked]
    if (tempIsClicked.includes(id)) {
      tempIsClicked.splice(seeMore.indexOf(id), 1)
    } else {
      tempIsClicked.push(id)
    }
    setIsClicked(tempSeeMore)
  }
        }
    
        return (
            <div className="body-wrapper w-full h-screen flex">
                <div className="sidebar w-1/6 2xl:w-1/8 h-full bg-sx-purple-dark-soft p-4 border-r-sx-pink border-r-2">
                    <div className="sidebar-body p-4">
                        <div className="link-wrapper">
                            <Link to="/dashboard/overview/">
                                <div className={[...isClicked].includes(1) && `${clickedClass}`} onClick={clickHandler(1)}>
                                    <img className="link-icon flex w-4 mr-4" src={imageLocation} alt="imageIcon"/>
                                    <div className="link-text">Overview</div>
                                </div>
                            </Link>
                            <Link to="/dashboard/planner/">
                                <div className={[...isClicked].includes(2) && `${clickedClass}`} onClick={clickHandler(2)}>
                                    <img className="link-icon flex w-4 mr-4" src={imagePlanner} alt="imageIcon"/>
                                    <div className="link-text ">Planner</div>
                                </div>
                            </Link>
                       </div>
                   </div>
               </div>
    ...
  • Related