skip to Main Content

On my website, data is displayed in a horizontal list. Each individual list item has a title and a button.
I’ve displayed it here https://codesandbox.io/p/sandbox/suspicious-platform-vj5td9

My task is that when you click on a div (id="main") with the value "first element", the color of the border changes from green to red. When you click on a div (id="main") with a value of "second element", the red color of the border with the "first element" is removed (and becomes green as before) and the border becomes red instead of the green of the "second element". However, when clicking on the "submenu" button, the border should not turn red.

    const data = [
  { id: "1", title: "first element" },
  { id: "2", title: "second element" },
  { id: "3", title: "third element" },
];

export default function App() {
  return (
    <div>
      {data.map((item) => (
        <div id="main" className="App">
          <div id="text">{item.title}</div>
          <button>submenu</button>
        </div>
      ))}
    </div>
  );
}

If you don’t understand something from my explanations, don’t hesitate to write to me.

2

Answers


  1. If you want to change the border of a div depending on where the user clicks, you can achieve this using JavaScript. Here’s a simple example using HTML, CSS, and JavaScript:

    function changeBorder(event) {
      // Get the clicked div
      const clickedDiv = event.target;
    
      // Get the current border color
      const currentBorderColor = window.getComputedStyle(clickedDiv).borderColor;
    
      // Change the border color based on the click position
      if (event.clientX < clickedDiv.offsetWidth / 2) {
        // Left half of the div
        clickedDiv.style.borderLeftColor = "red";
        clickedDiv.style.borderRightColor = currentBorderColor;
      } else {
        // Right half of the div
        clickedDiv.style.borderRightColor = "blue";
        clickedDiv.style.borderLeftColor = currentBorderColor;
      }
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <style>
        .clickable-div {
          width: 200px;
          height: 200px;
          border: 2px solid black;
          cursor: pointer;
        }
      </style>
      <title>Change Border on Click</title>
    </head>
    
    <body>
    
      <div id="myDiv" class="clickable-div" onclick="changeBorder(event)">
        Click me to change the border!
      </div>
    
    
    </body>
    
    </html>

    In this example, the changeBorder function is called when the div is clicked. The function checks the horizontal position of the click (event.clientX) relative to the width of the div to determine if the left or right side was clicked. It then changes the border color accordingly.

    You can customize this example based on your specific requirements and styling preferences.

    Login or Signup to reply.
  2. There were a few problems with your posted JSX, which we’ll discuss before looking at my proposed solution to the problem.

    So, the original code with explanatory, and critical, comments in the code:

    const data = [
      { id: "1", title: "first element" },
      { id: "2", title: "second element" },
      { id: "3", title: "third element" },
    ];
    
    export default function App() {
      return (
        /*   here you're returning the contents wrapped in a <div>.
             element; this isn't necessarily a problem but be aware
             of the potential for creating a mess of unnecessary
             <div> elements: */
        <div>
          /*   here we're looping over the data defined above,
               which is okay, except... */
          {data.map((item) => (
            /*   we're creating two elements, each of which have
                 an 'id' attribute, and there are multiple of
                 these elements in the eventual HTML, which
                 is invalid (an id must be unique within the
                 document): */
            <div id="main" className="App">
              <div id="text">{item.title}</div>
              <button>submenu</button>
            </div>
          ))}
        </div>
      );
    }
    

    My proposed solution, then, is as follows:

    
    import "./styles.css";
    
    const data = [
      { id: "1", title: "first element" },
      { id: "2", title: "second element" },
      { id: "3", title: "third element" },
    ];
    // defining a named function to handle the click
    // event, using an Arrow function expression,
    // which passes a reference to the Event Object
    // to the function:
    const clickHandler = (evt) => {
      // we retrieve all elements within the document that
      // have the 'activated' class-name:
      document
        .querySelectorAll(".activated")
        // and use NodeList.prototype.forEach() to iterate
        // over each of those elements and remove that
        // class-name:
        .forEach((el) => el.classList.remove("activated"));
    
      // we then use the currentTarget property-value of
      // the Event Object ('evt'), access its classList
      // and add the class of 'activated':
      evt.currentTarget.classList.add("activated");
    };
    
    export default function App() {
      return (
        /*   here we use a fragment to avoid returning the
             an unnecessary <div>: /*
        <>
          {
            /*   we define the <div id="main"> element 
                 outside of the loop that generates the
                 content: */
            <div id="main" className="App">
              {data.map((item) => (
               /*  here we avoid using id attributes, and 
                   instead use meaningful class-names (though
                   obviously you may wish to rename the
                   classes for your own use).
                   We then use the onClick approach to bind a
                   function (clickHandler) to the 'click' event
                   fired on the elements; I personally dislike
                   inline event-handling but it seems the
                   preferred means of doing it within React;
                   also (as I was preparing to finalise this)
                   I realised that React was complaining that
                     "Each child in a list should have a unique
                     "key" prop", so I added the "key" prop as
                    well: */
                <div className="menu-element-card" onClick={clickHandler} key={item.id}>
                  <h2>{item.title}</h2>
                  /*   in the even that these elements may,
                       in some circumstances, be nested within
                       a <form> I've taken the liberty of
                       adding 'type="button"' to the <button>
                       elements to prevent default/unintended
                       form-submission: */
                  <button type="button">sub-menu</button>
                </div>
              ))}
            <!-- closing the <div id="main"> element: -->
            </div>
          }
        <!-- closing the fragment: -->
        </>
      );
    }
    

    Also, I updated the stylesheet to the following; purely for aesthetics – please adjust for your own needs – in order to make the borders a little more prominent and spread the elements out a little:

    .App {
      display: flex;
      flex-flow: row nowrap;
      gap: 1rem;
    }
    .menu-element-card {
      border: 2px solid green;
      border-inline-start-width: 0.3rem;
      flex-grow: 1;
      margin-block-end: 0.4rem;
      padding-block: 0.4rem;
      padding-inline-start: 0.5rem;
      transition: border-color 300ms linear;
    }
    
    .activated {
      border-inline-start-color: red;
    }
    

    codesandbox.io demo.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search