Como criar um mapa interativo do Brasil com React

Mário
Mário
12 de janeiro de 2026

Mapas interativos são uma forma eficiente de comunicar informações geográficas em sites e aplicações. Em vez de listar estados ou regiões em texto, um mapa visual permite que o usuário entenda a cobertura ou presença de um serviço de forma imediata.

Neste post, mostro como criar um mapa do Brasil com React usando a biblioteca react-simple-maps. A técnica pode ser adaptada para qualquer país ou região, desde que você tenha o arquivo de dados geográficos correspondente.

Demo interativa

O objetivo

Criar um mapa interativo do Brasil onde estados específicos aparecem destacados. O mapa deve:

  • Renderizar todos os 27 estados brasileiros
  • Destacar estados selecionados com cor diferente
  • Mostrar tooltip com nome do estado no hover
  • Ter animação de entrada suave

A stack

  • React (ou Next.js)
  • react-simple-maps - biblioteca para renderizar mapas SVG
  • TopoJSON - formato de dados geográficos otimizado

Instalação

pnpm add react-simple-maps
pnpm add -D @types/react-simple-maps

Obtendo o TopoJSON do Brasil

O react-simple-maps precisa de um arquivo TopoJSON ou GeoJSON com as geometrias dos estados.

Fontes recomendadas:

Baixe o arquivo e salve em public/brazil-states.json.

Estrutura do TopoJSON

O arquivo tem esta estrutura:

{
  "type": "Topology",
  "objects": {
    "estados": {
      "type": "GeometryCollection",
      "geometries": [
        {
          "type": "Polygon",
          "properties": { "nome": "São Paulo" },
          "id": "SP",
          "arcs": [[...]]
        }
      ]
    }
  },
  "arcs": [...],
  "transform": {...}
}

Cada estado tem:

  • id: sigla do estado (SP, RJ, MG, etc.)
  • properties.nome: nome completo
  • arcs: coordenadas do polígono

Definindo os estados ativos

Crie um arquivo com as siglas dos estados que você quer destacar:

// lib/data/client-states.ts

export const activeStates: string[] = [
  "SP",  // São Paulo
  "MG",  // Minas Gerais
  "RJ",  // Rio de Janeiro
  "PR",  // Paraná
  "SC",  // Santa Catarina
  "RS",  // Rio Grande do Sul
  "BA",  // Bahia
  "DF",  // Distrito Federal
];

Componente do mapa

// components/BrazilMap.tsx

"use client";

import { useState, memo } from "react";
import {
  ComposableMap,
  Geographies,
  Geography,
} from "react-simple-maps";
import { activeStates } from "@/lib/data/client-states";

const GEO_URL = "/brazil-states.json";

interface HoveredState {
  name: string;
  code: string;
}

export function BrazilMap() {
  const [hovered, setHovered] = useState<HoveredState | null>(null);

  return (
    <div className="relative w-full max-w-lg mx-auto">
      <ComposableMap
        projection="geoMercator"
        projectionConfig={{
          center: [-54, -15],
          scale: 750,
        }}
        style={{ width: "100%", height: "auto" }}
      >
        <Geographies geography={GEO_URL}>
          {({ geographies }) =>
            geographies.map((geo) => {
              const stateCode = geo.id as string;
              const isActive = activeStates.includes(stateCode);

              return (
                <Geography
                  key={geo.rsmKey}
                  geography={geo}
                  fill={isActive ? "#d4a853" : "#e5e7eb"}
                  stroke="#fff"
                  strokeWidth={0.5}
                  style={{
                    default: { outline: "none" },
                    hover: {
                      fill: isActive ? "#1e3a5f" : "#d1d5db",
                      cursor: "pointer",
                    },
                    pressed: { outline: "none" },
                  }}
                  onMouseEnter={() => {
                    setHovered({
                      name: geo.properties.nome,
                      code: stateCode,
                    });
                  }}
                  onMouseLeave={() => setHovered(null)}
                />
              );
            })
          }
        </Geographies>
      </ComposableMap>

      {/* Tooltip */}
      {hovered && (
        <div className="absolute top-4 left-4 px-3 py-2 bg-gray-900 text-white text-sm rounded">
          {hovered.name} ({hovered.code})
        </div>
      )}
    </div>
  );
}

Entendendo o código

ComposableMap

Container principal do mapa. Configurações importantes:

  • projection: tipo de projeção cartográfica. geoMercator funciona bem para o Brasil
  • projectionConfig.center: coordenadas do centro do mapa [longitude, latitude]
  • projectionConfig.scale: zoom do mapa

Geographies

Carrega e processa o arquivo TopoJSON. Recebe o path do arquivo via prop geography.

Geography

Renderiza cada estado como um elemento SVG <path>. Props principais:

  • fill: cor de preenchimento
  • stroke: cor da borda
  • style: estilos para estados default, hover e pressed

Ajustando a projeção

Se o mapa aparecer cortado ou fora de posição, ajuste center e scale:

projectionConfig={{
  center: [-54, -15],  // longitude, latitude do centro
  scale: 750,          // zoom (maior = mais perto)
}}

Para o Brasil inteiro, valores entre 700-850 para scale funcionam bem.


Adicionando animação de entrada

Use CSS para animar os estados quando aparecem:

/* globals.css */

@keyframes state-fade-in {
  from { fill-opacity: 0; }
  to { fill-opacity: 1; }
}

.animate-state-fade-in {
  animation: state-fade-in 0.6s ease-out forwards;
  fill-opacity: 0;
}

Aplique a classe nos estados ativos:

<Geography
  className={isActive ? "animate-state-fade-in" : ""}
  style={{
    default: {
      animationDelay: `${index * 80}ms`,
    },
  }}
  // ...
/>

Isso cria um efeito de "cascata" onde cada estado aparece com um pequeno delay.


Otimização com memo

Para evitar re-renders desnecessários, extraia o Geography para um componente separado com memo:

const StateGeography = memo(function StateGeography({
  geo,
  isActive,
  onHover,
  onLeave,
}: Props) {
  return (
    <Geography
      geography={geo}
      fill={isActive ? "#d4a853" : "#e5e7eb"}
      // ...
    />
  );
});

Alternativas ao react-simple-maps

BibliotecaUso
react-simple-mapsMapas SVG estáticos, leve
Leaflet + react-leafletMapas interativos com tiles, zoom/pan
Mapbox GLMapas 3D, alta performance
D3.jsControle total, curva de aprendizado maior

Para um mapa simples de estados sem necessidade de zoom/pan, react-simple-maps é a escolha mais direta.


Referências