1

I have a map with 5 markers on it and accordion with 5 elements on the side. Each marker has a corresponding accordion.

I want to click on a marker and expand the corresponding accordion. Both accordion and markers on the map have the same key values (screenshot below).

enter image description here

I use Map() function to generate accordion as well as markers. Simplified code looks something like this:

function Markers() {
  const map = useMap();

  return (
    loc.map(loc => {
      return (
        <Marker
        icon={locationMarker}
        key={loc.properties.id} 
        position={[loc.properties.y, loc.properties.x]}}}>
        </Marker>
       )
    })
  )
}
export default Markers
function LocationCard() {

  return (
    <Container>
      {loc.map(loc => (
        <Accordion key={loc.properties.id}>
          <AccordionSummary>
            <Typography> {loc.properties.title} </Typography>
          </AccordionSummary>
          <AccordionDetails>
            <Typography> { loc.properties.description } </Typography>
          </AccordionDetails>
        </Accordion>  
      ))
      } 
    </Container>  
  );
}
export default LocationCard

I am basically looking for a functionality "On marker click, expand accordion".

Any idea how I can achieve this with my current setup?

Thanks

1 Answer 1

1

An accordion will internally store its own state (an uncontrolled component) to track if it's expanded but you can override it, making it a controlled component.

Go up the component tree of your markers + accordions to find the lowest common intersection where we can store some state and pass it down to both components.

Store the selected marker ID (or an array if you want to have many accordions open at once) and an event handler function to update the state when a marker is pressed.

const [selectedMarkerID, setSelectedMarkerID] = useState<number | undefined>();

const handleMarkerPressed = (id: number) => () => {
    // If a marker is pressed a second time, close the accordion
    setSelectedMarkerID(selectedMarkerID !== id ? id : undefined);
}

return (
<>
    <MyMarkers markers={markers} handleMarkerPressed={handleMarkerPressed />
    <MyAccordions markers={markers} selectedMarkerID={selectedMarkerID}  />
</>)

Then in your markers.map function, set the expanded property like the following:

<Accordion 
  key={loc.properties.id} 
  expanded={selectedMarkerID}>
  // If you want to disable opening of accordions, override the onClick
  onClick={undefined}
>

And your marker should look something like:

<Marker
  ...
  onClick={handleOpenMarker(marker.id)}
/>

An alternative to prop drilling the state + markers + event handler down both components would be some kind of store or context API

More info available in the MUI accordion docs

Edit Here's a Codebox example of passing the state + event handler around to manage which accordions are expanded: https://codesandbox.io/s/intelligent-feather-x9grwv?file=/src/App.tsx

The goal is to keep the markers in sync with the accordions, to summarise:

  • The accordion state is hoisted up a level to the App.tsx component
  • The marker event handler + accordion event handler is passed down from App.tsx
3
  • Sorry I'm a bit thick - still can't quite figure it out. I managed to retrieve the marker ID and save it in a state, but not sure how to instruct that particular accordion to expand on click. Expand and onChange props already look like this ` <Accordion expanded={expanded === loc.properties.id} onChange={handleChange(loc.properties.id)} > ` as I want to have the controlled accordion functionality as per the docs. Any idea what I can do to keep both interactions? Eg. accordion can expand either on marker or accordion click. And both actions should keep the controlled accordion behaviour.
    – Gatnik
    Commented Oct 29, 2022 at 16:37
  • haha no worries, I've added a codebox example which demonstrates the answer in more detail, clicking on either the button (marker placeholder) or accordion will update the state which will trigger an open or close event
    – Chris
    Commented Oct 31, 2022 at 6:38
  • Ah... it all works great. Really appreciate the effort, thanks!
    – Gatnik
    Commented Nov 6, 2022 at 18:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.