Maps

FeatureMapLibre GL

Interactive maps with MapLibre GL — open-source mapping for location features, markers, and geographic visualization.

Read this when adding maps to your app.
Useful for location pickers, store locators, or any geographic features.

Why MapLibre GL

MapLibre GL is an open-source fork of Mapbox GL. It provides beautiful vector maps without vendor lock-in or usage-based pricing. You can use free tile providers or host your own.

Catalyst uses react-map-gl as the React wrapper, which provides a declarative API for MapLibre. You get markers, popups, controls, and layers — all as React components.

Key Features

What you can build with maps:

Markers

Point locations. Place markers for stores, events, or any point of interest.

Controls

Navigation UI. Zoom, rotation, geolocation, and fullscreen controls.

Layers

Custom visualization. Heatmaps, clusters, and data-driven styling.

Catalyst Integration

Catalyst includes map examples and configuration:

app/(examples)/examples/maps/

Map examples with markers and interactions

Quick Start

Basic map

"use client"
import Map from "react-map-gl/maplibre"
import "maplibre-gl/dist/maplibre-gl.css"

export function LocationMap() {
  return (
    <Map
      initialViewState={{
        longitude: -122.4,
        latitude: 37.8,
        zoom: 12,
      }}
      style={{ width: "100%", height: 400 }}
      mapStyle="https://basemaps.cartocdn.com/gl/positron-gl-style/style.json"
    />
  )
}

Map with markers

import Map, { Marker, Popup } from "react-map-gl/maplibre"
import { useState } from "react"

const locations = [
  { id: 1, name: "Office", lng: -122.4, lat: 37.8 },
  { id: 2, name: "Warehouse", lng: -122.5, lat: 37.7 },
]

export function LocationsMap() {
  const [selected, setSelected] = useState(null)

  return (
    <Map
      initialViewState={{ longitude: -122.4, latitude: 37.8, zoom: 10 }}
      style={{ width: "100%", height: 400 }}
      mapStyle="https://basemaps.cartocdn.com/gl/positron-gl-style/style.json"
    >
      {locations.map((loc) => (
        <Marker
          key={loc.id}
          longitude={loc.lng}
          latitude={loc.lat}
          onClick={() => setSelected(loc)}
        />
      ))}

      {selected && (
        <Popup
          longitude={selected.lng}
          latitude={selected.lat}
          onClose={() => setSelected(null)}
        >
          {selected.name}
        </Popup>
      )}
    </Map>
  )
}

Free Map Styles

These tile providers offer free tiers:

CartoDB Positron

Light, minimal style — great for data visualization

https://basemaps.cartocdn.com/gl/positron-gl-style/style.json

CartoDB Dark Matter

Dark style — works well with dark mode

https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json

CartoDB Voyager

Colorful style — good for general purpose

https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json

For production apps with high traffic, consider MapTiler or Stadia Maps for reliable tile hosting.

Tips

Import the CSS. MapLibre needs its stylesheet for controls and popups to render correctly.

Use "use client". Maps require browser APIs and must be client components.

Set explicit dimensions. The map container needs width and height — it won't grow to fill without them.

Handle loading state. Maps can take a moment to load tiles. Consider showing a loading indicator.

Learn More

For AI Agents

Key rules:

  • Import from react-map-gl/maplibre
  • Import maplibre-gl/dist/maplibre-gl.css
  • Maps must be client components ("use client")
  • Set explicit width and height on the Map
  • Use free CartoDB styles for development
  • See /examples/maps for usage patterns