J
JereCodes
Galleries
J
JereCodes
Galleries
Back to Blog

The Fastest Quickstart to Web Maps with React

Jere on October 26, 2025
•
4 min read
react
maps
maplibre
react-map-gl
geojson
tutorial

Need to add an interactive map to your React app? Here's the fastest way to get started with zero backend setup, no API keys, and full control over your map styling.

Why This Stack?

I've tried many mapping solutions, and this combination is unbeatable for speed:

  • react-map-gl: Clean React wrapper for MapLibre GL
  • OpenFreeMap: Free, open-source map tiles (no API key needed!)
  • GeoJSON: Simple format for custom markers and data
  • MapLibre GL: Fast, modern web mapping library

Quick Setup

Install the dependencies:

pnpm install react-map-gl maplibre-gl

That's it. No API keys, no accounts, no configuration files.

Basic Map Component

Here's a complete working map in just a few lines:

'use client'
import { Map } from 'react-map-gl/maplibre';
import 'maplibre-gl/dist/maplibre-gl.css';

export default function MapComponent() {
  return (
    <Map
      initialViewState={{
        longitude: 0,
        latitude: 40,
        zoom: 2
      }}
      style={{ width: "100%", height: "100vh" }}
      mapStyle="https://tiles.openfreemap.org/styles/bright"
    />
  );
}

That's a fully interactive map with panning, zooming, and rotation. Ship it.

Live Demo

Here's what we just built - a working interactive map with custom markers:

Try panning, zooming, and exploring. That's 3 cities marked on a real map, and you built it in minutes.

Adding Custom Markers

Want to show locations? Create a simple JSON file with your data:

[
  {
    "name": "Helsinki",
    "country": "Finland",
    "coordinates": [24.9384, 60.1699]
  },
  {
    "name": "Berlin",
    "country": "Germany",
    "coordinates": [13.4050, 52.5200]
  }
]

Then convert it to GeoJSON and add it as a layer:

import { Map, Source, Layer } from 'react-map-gl/maplibre';
import citiesData from './cities.json';

const citiesGeoJSON = {
  type: 'FeatureCollection' as const,
  features: citiesData.map(city => ({
    type: 'Feature' as const,
    geometry: {
      type: 'Point' as const,
      coordinates: city.coordinates
    },
    properties: {
      name: city.name,
      country: city.country
    }
  }))
};

const cityLayer = {
  id: 'cities',
  type: 'circle' as const,
  paint: {
    'circle-radius': 8,
    'circle-color': '#ffffff',
    'circle-stroke-width': 2.5,
    'circle-stroke-color': '#000000'
  }
};

export default function MapComponent() {
  return (
    <Map
      initialViewState={{
        longitude: 0,
        latitude: 40,
        zoom: 2
      }}
      style={{ width: "100%", height: "100vh" }}
      mapStyle="https://tiles.openfreemap.org/styles/bright"
    >
      <Source id="cities-source" type="geojson" data={citiesGeoJSON}>
        <Layer {...cityLayer} />
      </Source>
    </Map>
  );
}

Multiple Marker Types

Need different marker styles? Just add more layers:

const airportLayer = {
  id: 'airports',
  type: 'circle' as const,
  paint: {
    'circle-radius': 5,
    'circle-color': '#3498db',
    'circle-stroke-width': 1,
    'circle-stroke-color': '#ffffff',
    'circle-opacity': 0.7
  }
};

// In your component:
<Source id="airports-source" type="geojson" data={airportsGeoJSON}>
  <Layer {...airportLayer} />
</Source>
<Source id="cities-source" type="geojson" data={citiesGeoJSON}>
  <Layer {...cityLayer} />
</Source>

Layers render in order - later layers appear on top.

Map Style Switcher

Want to let users choose map styles? Add a simple dropdown:

import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";

const mapStyles = [
  { name: 'Liberty', url: 'https://tiles.openfreemap.org/styles/liberty' },
  { name: 'Bright', url: 'https://tiles.openfreemap.org/styles/bright' },
  { name: 'Positron', url: 'https://tiles.openfreemap.org/styles/positron' },
  { name: 'Dark Matter', url: 'https://tiles.openfreemap.org/styles/dark-matter' }
];

export default function MapComponent() {
  const [mapStyle, setMapStyle] = useState(mapStyles[0].url);

  return (
    <div style={{ position: 'relative', width: '100%', height: '100vh' }}>
      <Map mapStyle={mapStyle} {...otherProps}>
        {/* layers */}
      </Map>
      
      <div style={{ position: 'absolute', top: '20px', right: '20px', zIndex: 1000 }}>
        <Select value={mapStyle} onValueChange={setMapStyle}>
          <SelectTrigger className="w-[180px] bg-background">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {mapStyles.map((style) => (
              <SelectItem key={style.url} value={style.url}>
                {style.name}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>
    </div>
  );
}

Why This Approach Works

No API Keys Required: OpenFreeMap is truly free and open. No rate limits, no registration, no tracking.

Simple Data Format: JSON files you can edit in any text editor. No database, no backend API needed for static data.

Type-Safe: TypeScript works beautifully with this setup. Your data structure is explicit.

Performant: MapLibre GL uses WebGL for smooth rendering even with thousands of markers.

Customizable: Full control over styling with MapLibre's powerful paint properties.

Real-World Example

I used this exact stack to visualize 45 airports I've visited and 6 cities I've lived in. The entire implementation took less than an hour:

  • Simple JSON files for data
  • Different marker styles for airports vs cities
  • Map style switcher for light/dark themes
  • Zero configuration or build complexity

Going Further

This foundation scales surprisingly well:

  • Popups: Add click handlers and show detail panels - Popup API docs
  • Clustering: MapLibre has built-in support for marker clustering - Clustering guide
  • Lines and Polygons: GeoJSON supports LineString and Polygon geometries - GeoJSON layers
  • Heat Maps: Change the layer type to heatmap - Heatmap layer
  • Custom Tiles: Host your own map tiles for complete control - Style spec

Key Takeaways

  • Start simple: Basic map + markers is often enough
  • Use static JSON for data that doesn't change frequently
  • OpenFreeMap eliminates API key complexity
  • MapLibre GL is production-ready and actively maintained
  • The react-map-gl wrapper keeps your React code clean

Web maps don't have to be complicated. This stack proves you can build something useful in minutes, not days.

Now go build something! 🗺️

Share Article

J

About Jere

Software developer passionate about indoor mapping, web technologies, and building useful tools.

GitHubTwitter/XYouTube