How to Add Interactive Maps to Your Personal Website

July 7, 2025 (3d ago)

How to Add Interactive Maps to Your Personal Website

Static lists of places you've been can be dull. Interactive maps, on the other hand, offer a dynamic and visually engaging way to tell your story. On my personal website, I've included two distinct maps: a world map to showcase the countries I've visited, and a detailed map of Hong Kong highlighting my favorite local spots.

This guide will walk you through the technical implementation of both maps, providing a step-by-step tutorial for you to integrate similar features into your own projects.

Part 1: The World Map with react-simple-maps

For a clean, stylized, and lightweight world map, react-simple-maps is an excellent choice. It's a React library that makes it easy to create projections, add interactivity, and customize your map's appearance.

The implementation for this map can be found in src/components/world-map.tsx.

Step 1: Get Your Map Data and Set Up the Component

First, you'll need geographic data for the world's countries, typically in TopoJSON or GeoJSON format. You can find files like world-countries.json online. Once you have your data, you can set up the main map component.

The ComposableMap component acts as a container for your map. Inside, the Geographies component fetches and parses your JSON data.

// src/components/world-map.tsx
import { ComposableMap, Geographies, Geography } from "react-simple-maps";
import geoData from "../../public/world-countries.json"; // Your map data
 
const WorldMap = () => (
  <ComposableMap
    projection="geoMercator"
    projectionConfig={% raw %}{{
      scale: 150, // Adjust the scale to zoom in/out
    }}{% endraw %}
  >
    <Geographies geography={geoData}>
      {({ geographies }) =>
        geographies.map((geo) => (
          <Geography key={geo.rsmKey} geography={geo} />
        ))
      }
    </Geographies>
  </ComposableMap>
);

Step 2: Highlight Visited Countries

To make the map your own, you can highlight the countries you've visited. Create an array of the countries' ISO 3166-1 alpha-3 codes and use it to conditionally style each Geography component.

// src/components/world-map.tsx
 
const visitedCountries = [
  "USA", "CHN", "JPN", "FRA", // and so on...
];
 
// Inside the component...
const isVisited = visitedCountries.includes(geo.id);
 
return (
  <Geography
    key={geo.rsmKey}
    geography={geo}
    style={% raw %}{{
      default: {
        fill: isVisited ? "#5AC8FA" : "#E5E7EB", // Visited color vs. default
        outline: "none",
      },
      hover: {
        fill: "#007AFF", // Hover color
        outline: "none",
      },
    }}{% endraw %}
  />
);

This code checks if a country's ID (its ISO code) is present in the visitedCountries array and applies a different fill color if it is.

Step 3: Add Interactivity with Tooltips

A simple tooltip that shows the country's name on hover adds a great layer of interactivity. This can be managed with a React state hook.

// src/components/world-map.tsx
const [hoveredCountry, setHoveredCountry] = useState<string | null>(null);
 
//...
<Geography
  //...
  onMouseEnter={() => setHoveredCountry(geo.properties.name)}
  onMouseLeave={() => setHoveredCountry(null)}
/>
 
//... and render the tooltip conditionally
{hoveredCountry && (
  <div className="absolute top-2 left-1/2 transform -translate-x-1/2 bg-white p-2 rounded shadow">
    {hoveredCountry}
  </div>
)}

The onMouseEnter and onMouseLeave events update the state, which in turn shows or hides the tooltip.

Part 2: A Detailed Local Map with react-leaflet

When you need a more detailed, zoomable map with custom markers, react-leaflet is the perfect tool. It provides a React wrapper around the popular Leaflet.js library.

The implementation for this map is in src/components/hong-kong-map.tsx.

Step 1: Set Up the Leaflet Map Container

The MapContainer component from react-leaflet creates the map. You'll also need a TileLayer, which fetches map tiles from a service like OpenStreetMap.

// src/components/hong-kong-map.tsx
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css"; // Don't forget to import the CSS
 
const HongKongMap = () => (
  <MapContainer center={[22.35, 114.15]} zoom={10} style={% raw %}{{ height: '400px', width: '100%' }}{% endraw %}>
    <TileLayer
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      attribution='&copy; OpenStreetMap contributors'
    />
    {/* Markers will be rendered here */}
  </MapContainer>
);

Step 2: Define Custom Markers and Locations

To highlight specific spots, you'll need their coordinates. You can store this data in an object. For a more personalized touch, you can create custom icons for your markers.

// src/components/hong-kong-map.tsx
import L from "leaflet";
 
// Define custom icons
const natureIcon = new L.Icon({
  iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png',
  iconSize: [25, 41],
  iconAnchor: [12, 41],
});
 
// Define your locations
const locations = {
  "Tai Mo Shan": {
    name: "Tai Mo Shan (大帽山)",
    coordinates: [22.4197, 114.1175],
    type: "nature"
  },
  // ... more locations
};

Step 3: Render Markers and Popups

Finally, map over your locations data to render a Marker for each spot. Use the icon prop to apply your custom icons and add a Popup to display more information when a marker is clicked.

// Inside the MapContainer
{Object.entries(locations).map(([key, location]) => (
  <Marker
    key={key}
    position={location.coordinates as [number, number]}
    icon={location.type === 'nature' ? natureIcon : urbanIcon}
  >
    <Popup>
      <span className="font-semibold">{location.name}</span>
      <br />
      {location.description}
    </Popup>
  </Marker>
))}

This will place a marker for each location on the map, complete with a custom icon and a popup that reveals more details on click.

Conclusion

By following these steps, you can create beautiful and informative maps that add a personal and professional touch to your website. The combination of react-simple-maps for global visualization and react-leaflet for detailed local exploration provides a comprehensive mapping solution that can showcase your travels and experiences in an engaging way.

The key benefits of this approach include:

  • Visual storytelling: Maps provide an immediate visual impact that text alone cannot achieve
  • Interactive engagement: Users can explore your experiences through hover effects and clickable markers
  • Responsive design: Both libraries work well across different screen sizes
  • Customization: You can tailor colors, icons, and interactions to match your website's design
  • Performance: Lightweight libraries ensure fast loading times

Whether you're showcasing your global travels or highlighting local favorites, interactive maps can transform your personal website into a more engaging and memorable experience for your visitors.