Search code examples
reactjsnext.jsreact-tooltipreact-simple-maps

ReactTooltip (npm package) not rendering or visible in NextJS 14, React 18 on hovering over Interactive SVG of the map displayed via React-Simple-Maps


I am using React-Simple-Maps to manipulate and render an SVG of a map (a chloropeth map). I am using React-Tooltip to display a tooltip over each constituency on the map, displaying their full names and an option for "more detail." So far, I haven't been able to render even the names, let alone a fully stylized div with the aforementioned details.

Using the documentation available on the sites of both respective libraries, I've ended up doing something like this (with no success). Here is the codesandbox link, which I followed: https://codesandbox.io/s/map-chart-with-tooltip-forked-42sldc?file=/src/index.js

The Map component code (note that on mouseEnter, I was able to log the names onto the console, but I don't know why it's not setting up for the content of the tooltip, or if anything else is an issue). Ignore the marker (you may comment it out if you wish to run or test the code).

const MapChart = ({
  setTooltipContent,
}: {
  setTooltipContent: (content: string) => void;
}) => {
  return (
    <div id='map' className=''>
      <ComposableMap className='stroke-black'>
        <Geographies
          geography={SgMap}
          fill='#D6D6DA'
          stroke='#FFFFFF'
          className=''
        >
          {({ geographies }) =>
            geographies.map((geo) => (
              <Geography
                key={geo.rsmKey}
                geography={geo}
                onMouseEnter={() => {
                  setTooltipContent(geo.properties.name);
                }}
                onMouseLeave={() => {
                  setTooltipContent('');
                }}
                 data-tip
                data-for='map'
                style={{
                  default: {
                    fill: '#D6D6DA',
                    outline: 'none',
                  },
                  hover: {
                    fill: '#F53',
                    outline: 'none',
                  },
                  pressed: {
                    fill: '#E42',
                    outline: 'none',
                  },
                }}
              />
            ))
          }
        </Geographies>
        {ConstituenciesNamesandCoordinates.map(({ name, coordinates }, i) => (
          <Marker key={i} coordinates={coordinates}>
            <text
              textAnchor='middle'
              y={-10}
              className='font-times text-[0.5rem] text-black'
              style={{
                userSelect: 'none',
                pointerEvents: 'none',
                fontWeight: 100,
              }}
            >
              {name}
            </text>
          </Marker>
        ))}
      </ComposableMap>
    </div>
  );
};

The code where i am trying to render the tooltip

import MapChart from "./MapComponent";


const MapSection=()=> {
  const [content, setContent] = useState("");
  return (
    <div>
      <MapChart setTooltipContent={setContent} />
      <Tooltip data-tooltip-id="map" content={content} float />
    </div>
  );
}


export default MapSection;

Any help would be much appreciated. The Sandbox version works; btw, mine doesn't for some reason.


Solution

  • If using react-tooltip v5.13.0 or newer, then the typical basic usage would be to add an id attribute to the react-tooltip component; <Tooltip /> (e.g. my-tooltip), like so:

    import { Tooltip } from 'react-tooltip'
    
    // ...
    
    <Tooltip id="my-tooltip" content={content} float />
    

    And then, within each mapped <Geography> component, you would set the data attribute; data-tooltip-id="my-tooltip", whereby this is how the react-tooltip component would reference to each geography / constituent:

    import { ComposableMap, Geographies, Geography } from "react-simple-maps";
    
    // ... 
    
    <ComposableMap className='stroke-black'>
      <Geographies
        geography={SgMap}
        fill='#D6D6DA'
        stroke='#FFFFFF'
      >
        {({ geographies }) =>
          geographies.map((geo) => (
            <Geography
              key={geo.rsmKey}
              geography={geo}
              data-tooltip-id="my-tooltip"
              onMouseEnter={() => setTooltipContent(geo.properties.name)}
              onMouseLeave={() => setTooltipContent("")}
            />
          ))
        }
      </Geographies>
    </ComposableMap>
    

    Also, as a bonus, if you're simply rendering plain simple content (e.g. constituent / geography country name) in the tooltip for each <Geography>, then you may be able to get away with not needing to maintain a local component state at all, by omitting the need for content={content}, and just set another data attribute; data-tooltip-content on <Geography>, like so:

    import { ComposableMap, Geographies, Geography } from "react-simple-maps";
    
    // ... 
    
    <ComposableMap className='stroke-black'>
      <Geographies
        geography={SgMap}
        fill='#D6D6DA'
        stroke='#FFFFFF'
      >
        {({ geographies }) =>
          geographies.map((geo) => (
            <Geography
              key={geo.rsmKey}
              geography={geo}
              data-tooltip-id="my-tooltip"
              data-tooltip-content={geo.properties.name}
            />
          ))
        }
      </Geographies>
    </ComposableMap>
    

    Source documentation: https://react-tooltip.com/docs/getting-started#using-anchor-data-attributes