npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-maplibre-lite

v0.2.7

Published

Lightweight MapLibre GL JS wrapper using WebView

Readme

react-native-maplibre-lite

Lightweight MapLibre for React Native powered by WebView.

react-native-maplibre-lite renders a bundled MapLibre GL JS runtime inside a React Native app and exposes a small React API:

  • MapView
  • Marker
  • Polyline
  • Polygon

It is designed for teams that want a practical MapLibre integration without native SDK setup complexity.

Screenshots

  • MapLibre GL JS in a React Native component
  • Declarative overlays: Marker, Polyline, Polygon
  • Built-in PMTiles protocol support
  • Built-in 3D building extrusion for compatible vector styles
  • Imperative camera methods: fitBounds() and flyTo()
  • Optional autoFitBounds for markers, polylines and polygons
  • Custom marker icons or marker HTML
  • Optional navigator mode with GraphHopper routes, HUD, route snapping and rerouting
  • Map style caching through AsyncStorage
  • Android performance controls: performanceMode, turboWhileMoving, pixelRatio

Installation

npm install react-native-maplibre-lite react-native-webview @react-native-async-storage/async-storage @sayem314/react-native-keep-awake @react-native-community/geolocation react-native-svg react-native-video

or

yarn add react-native-maplibre-lite react-native-webview @react-native-async-storage/async-storage @sayem314/react-native-keep-awake @react-native-community/geolocation react-native-svg react-native-video

react-native-svg and react-native-video are used by the navigator UI: the maneuver/HUD icons are drawn with SVG, and voice guidance clips are played with react-native-video. They are only needed when you enable navigator.

Quick Start

import React, { useRef } from 'react';
import { Button, View } from 'react-native';
import MapView, {
  Marker,
  Polyline,
  Polygon,
  type MapViewRef,
} from 'react-native-maplibre-lite';

export function MapScreen() {
  const mapRef = useRef<MapViewRef>(null);

  return (
    <View style={{ flex: 1 }}>
      <MapView
        ref={mapRef}
        style={{ flex: 1 }}
        placeholderTheme="light"
        center={[37.6173, 55.7558]}
        zoom={11}
        mapStyle="https://demotiles.maplibre.org/style.json"
        zoomEnabled
        scrollEnabled
        autoFitBounds
        fitBoundsPadding={48}
        onReady={() => console.log('map ready')}
      >
        <Marker
          uniqueId="m-1"
          latitude={55.7558}
          longitude={37.6173}
          color="#1D4ED8"
          onPress={() => console.log('marker pressed')}
        />

        <Polyline
          uniqueId="line-1"
          color="#2563EB"
          width={4}
          coordinates={[
            [37.61, 55.75],
            [37.63, 55.76],
            [37.65, 55.74],
          ]}
        />

        <Polygon
          uniqueId="poly-1"
          fillColor="#2563EB"
          fillOpacity={0.15}
          strokeColor="#2563EB"
          strokeWidth={2}
          coordinates={[
            [37.6, 55.75],
            [37.62, 55.77],
            [37.66, 55.75],
            [37.6, 55.75],
          ]}
        />
      </MapView>

      <Button
        title="Fly to Moscow center"
        onPress={() => mapRef.current?.flyTo([37.6173, 55.7558], 14)}
      />
    </View>
  );
}

Coordinates use [longitude, latitude], the same order as GeoJSON and GraphHopper. Marker props still accept latitude and longitude separately.

Navigator Mode

Navigator mode adds a route line, a current-position arrow, a driving HUD and GraphHopper-based route recalculation.

The route line and position arrow are drawn inside the WebView, while the instruction HUD, the recenter / voice floating buttons and voice playback are rendered natively by MapView. The WebView streams a HUD view-model and full voice phrase text to the native side; the native side renders the UI (react-native-svg), calls your ttsHandler to obtain audio URLs and plays them (react-native-video), owning voice selection, volume and persistence (AsyncStorage). Tapping the recenter button sends a command back to the WebView to recenter the camera.

import React, { useRef } from 'react';
import { Button, View } from 'react-native';
import MapView, { type MapViewRef } from 'react-native-maplibre-lite';

export function NavigatorScreen() {
  const mapRef = useRef<MapViewRef>(null);

  return (
    <View style={{ flex: 1 }}>
      <MapView
        ref={mapRef}
        style={{ flex: 1 }}
        center={[37.6173, 55.7558]}
        zoom={17}
        mapStyle="https://example.com/style.json"
        navigator
        graphhopperUrl="https://graphhopper.example.com"
        navigatorLang="ru"
        navigatorProfile="bike"
        navigatorChrome={{ accent: '#22c55e', routeLine: '#22c55e' }}
        zoomEnabled
        scrollEnabled
        onNavigatorRouteSet={(route) => console.log('route', route)}
        onNavigatorInstruction={(instruction) =>
          console.log('next instruction', instruction)
        }
        onNavigatorPositionSet={(position) => console.log('position', position)}
        onMapLiteError={(error) => console.warn(error)}
      />

      <Button
        title="Build route"
        onPress={() => mapRef.current?.setNavigatorPoint(55.76, 37.64)}
      />
    </View>
  );
}

graphhopperUrl is the base URL without the required /route suffix. The plugin sends POST {graphhopperUrl}/route with points_encoded: false, instructions: true, locale from navigatorLang, and profile from navigatorProfile (defaults to car when omitted or when the string is not a known profile; see NAVIGATOR_PROFILE_IDS in the package exports).

Use setNavigatorPosition(latitude, longitude) to feed real GPS updates. The WebView side snaps the position to the route, marks arrival, or reroutes when the point is too far from the current route. pickNavigatorPosition() is a development helper: the next tap on the map becomes the current navigator position.

Voice guidance (TTS)

Pass ttsVoices and ttsHandler on MapView to enable voice guidance and the native voice floating button. The WebView builds localized phrase text from embedded dictionaries (ru / en, keyed by navigatorLang) and sends the full string to React Native. Your handler synthesizes audio and returns a URL; the library plays it and caches URLs per voice and text.

<MapView
  navigator
  navigatorLang="ru"
  ttsVoices={{ silero_kseniya: 'Ксения', silero_aidar: 'Айдар' }}
  ttsHandler={async (text, voiceKey) => {
    const res = await fetch('https://your-tts.example/speak', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ text, voice: voiceKey }),
    });
    const { url } = (await res.json()) as { url: string };
    return url;
  }}
  /* … */
/>

See webProject/NAVIGATION_VOICE.md for phrase keys and announcement rules.

Navigator chrome (navigatorChrome)

Optional object passed as navigatorChrome on MapView. accent, routeLine and routeOutline are forwarded to the WebView (route line and arrow); the hud* keys theme the native HUD panel and the floating buttons. All keys are optional; omit the prop to keep the default blue theme.

| Key | Purpose | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | accent | Accent in hex (#rgb / #rrggbb): map arrow gradient and maneuver icon tile in the HUD (tile background and icon color are derived from it). | | routeLine | Main route line color (library default was #3b82f6). | | routeOutline | Wide underlay for the route line (default was #1e3a8a). | | hudBackground | HUD panel background: any valid CSS value (rgba(...), linear-gradient(...), etc.). | | hudForeground | Primary text color on the HUD. | | hudMuted | Secondary text (street, summary, ETA); when this is hex, the divider tone is derived from it. |

Speed limit styling on the HUD is not configurable.

Route simulation (navigatorSimulate, debug)

Pass navigatorSimulate (or call setNavigatorSimulation(true) on the ref) to auto-drive the navigator marker along the built route. Once a route exists (setNavigatorPoint), the WebView steps the marker along the polyline at a fixed speed, feeding each point through the same pipeline as real GPS — so the arrow, camera, HUD, instruction advance and voice all behave as on a real trip. This is a dev/debug aid: while it is on, real device GPS is not forwarded to the WebView, and the simulation stops automatically on arrival. Requires navigator: true.

API

MapView props

| Prop | Type | Required | Description | | ---------------------------- | ------------------------------------------ | -------- | -------------------------------------------------------------------------------------- | | center | [number, number] | yes | Initial map center as [lng, lat] | | zoom | number | yes | Initial zoom level | | mapStyle | string | yes | MapLibre style URL. The style JSON is fetched and cached with AsyncStorage | | style | StyleProp<ViewStyle> | yes | Container style | | placeholderTheme | 'light' \| 'dark' | no | Placeholder theme before map init. Defaults to light | | minZoom | number | no | Minimum zoom | | maxZoom | number | no | Maximum zoom | | zoomEnabled | boolean | no | Enable double-tap zoom, pinch zoom and rotation | | scrollEnabled | boolean | no | Enable pan and scroll gestures | | showSelectPoint | boolean | no | Show animated center pointer | | selectPointColor | string | no | Center pointer color | | selectPointBackgroundColor | string | no | Center pointer background | | autoFitBounds | boolean | no | Automatically fit camera to visible overlays after overlay changes | | fitBoundsPadding | number | no | Padding for fitBounds() and autoFitBounds. Defaults to 40 | | fitBoundsDuration | number | no | Animation duration for fitBounds(). Defaults to 500 | | flyToDuration | number | no | Animation duration for flyTo(). Defaults to 500 | | performanceMode | 'quality' \| 'balanced' \| 'performance' | no | Rendering quality/performance profile | | pixelRatio | number | no | Manual renderer pixel ratio override | | turboWhileMoving | boolean | no | Hide polyline/polygon overlays while map moves | | debugMode | boolean | no | Enables extra WebView-side debug alerts/logging | | navigator | boolean | no | Enable navigator mode | | graphhopperUrl | string | no | Base GraphHopper URL for navigator routes | | navigatorLang | 'ru' \| 'en' | no | Navigator HUD and instruction language. Defaults to ru | | navigatorProfile | NavigatorProfile \| string | no | GraphHopper routing profile (car, bike, foot, …). Unknown → car | | navigatorChrome | NavigatorChromeParams | no | Navigator colors: route line, arrow accent, native HUD/FAB theme (see section above) | | ttsVoices | Record<string, string> | no | TTS voice key → user-visible label. With ttsHandler, enables voice guidance + FAB | | ttsHandler | (text, voiceKey) => Promise<string> | no | Synthesize phrase text to an audio URL for playback | | navigatorSimulate | boolean | no | Dev-only: auto-drive the marker along the built route (trip simulation). Suspends real GPS forwarding while on | | onReady | () => void | no | Called after the WebView map is initialized | | onMoveStart | (params) => void | no | movestart event | | onMoveEnd | (params) => void | no | moveend event | | onZoomStart | (params) => void | no | zoomstart event | | onZoomEnd | (params) => void | no | zoomend event | | onIdle | (params) => void | no | idle event | | onNavigatorRouteSet | (params) => void | no | Called after navigator route creation | | onNavigatorInstruction | (params) => void | no | Called when a navigator instruction is advanced | | onNavigatorPositionSet | (params) => void | no | Called after navigator position update/snap/reroute | | onMapLiteError | (error) => void | no | WebView command error callback | | useNativeMapHtml | boolean | no | Load map.html from native app resources instead of inline MAP_HTML. See below | | developerLocalhostBundleUrl| string | no | Dev-only: load WebView bundle from a local URL instead of inline or native map.html |

MapView ref

| Method | Description | | ------------------------------------------- | ----------------------------------------------------------------- | | fitBounds() | Fits camera to current markers, polylines and polygons | | flyTo(center, zoom) | Animates camera to [lng, lat] and zoom | | setNavigatorPoint(latitude, longitude) | Builds a navigator route to the destination. Requires navigator | | advanceNavigatorInstruction() | Advances to the next navigator instruction | | setNavigatorPosition(latitude, longitude) | Updates current navigator position from GPS or another source | | pickNavigatorPosition() | Dev helper: next map tap sets current navigator position | | setNavigatorSimulation(enabled) | Dev helper: start/stop the route trip simulation (same as navigatorSimulate prop) |

Marker props

| Prop | Type | Required | Description | | ----------------- | ------------ | -------- | ----------------------------------------------------------------------------- | | uniqueId | string | yes | Unique overlay id | | latitude | number | yes | Marker latitude | | longitude | number | yes | Marker longitude | | onPress | () => void | no | Press callback | | ignoreFitBounds | boolean | no | Exclude marker from fitBounds() and autoFitBounds | | color | string | no | Default MapLibre marker color | | iconUrl | string | no | Custom marker image URL | | iconWidth | number | no | Custom icon width | | iconHeight | number | no | Custom icon height | | html | string | no | Custom marker HTML. If provided, it takes priority over iconUrl and color |

Polyline props

| Prop | Type | Required | Description | | ----------------- | -------------------- | -------- | --------------------------------------------------- | | uniqueId | string | yes | Unique overlay id | | coordinates | [number, number][] | yes | Line coordinates as [lng, lat] | | ignoreFitBounds | boolean | no | Exclude line from fitBounds() and autoFitBounds | | color | string | no | Line color. Defaults to #000000 | | width | number | no | Line width. Defaults to 4 |

Polygon props

| Prop | Type | Required | Description | | ----------------- | -------------------- | -------- | ------------------------------------------------------ | | uniqueId | string | yes | Unique overlay id | | coordinates | [number, number][] | yes | Polygon ring coordinates as [lng, lat] | | ignoreFitBounds | boolean | no | Exclude polygon from fitBounds() and autoFitBounds | | fillColor | string | no | Fill color | | fillOpacity | number | no | Fill opacity | | strokeColor | string | no | Stroke color | | strokeOpacity | number | no | Stroke opacity | | strokeWidth | number | no | Stroke width |

Performance Tuning (Android)

Start with:

<MapView
  // ...
  performanceMode="performance"
  turboWhileMoving
/>

Profiles:

  • quality: best visual quality
  • balanced: default on Android; better FPS with moderate quality reduction
  • performance: aggressive optimizations, lower renderer resolution, simplified style and reduced map effects

Tips:

  • If you still see frame drops, pass a lower pixelRatio, for example 0.75
  • Keep number of simultaneously visible overlays moderate
  • Prefer simpler map styles with fewer labels and 3D layers

Native map.html bundle

By default, MapView loads the map runtime as inline HTML from the generated webMapBuild.ts bundle (MAP_HTML). For smaller JS bundle size or to update the WebView runtime without republishing the npm package, copy resources/map.html into your native app and enable useNativeMapHtml:

<MapView
  useNativeMapHtml
  style={{ flex: 1 }}
  center={[37.6173, 55.7558]}
  zoom={11}
  mapStyle="https://demotiles.maplibre.org/style.json"
/>

WebView source priority: developerLocalhostBundleUrluseNativeMapHtml → inline MAP_HTML.

Android

Copy map.html from the package (node_modules/react-native-maplibre-lite/resources/map.html) or from this repo after building webProject:

android/app/src/main/assets/map.html

Create the assets folder if it does not exist. MapView loads it as file:///android_asset/map.html.

iOS

Copy map.html into your app project, for example:

ios/MyApp/map.html

In Xcode:

  1. Drag map.html into the project tree (not only into Finder).
  2. Enable Copy items if needed and select your app target.
  3. Confirm the file appears under Build Phases → Copy Bundle Resources.

The URI is resolved automatically from the .app bundle path (release / standalone builds). In Metro dev builds on iOS, prefer the default inline HTML or developerLocalhostBundleUrl.

Updating map.html

After changes in webProject, rebuild and recopy the file into both platforms:

cd webProject
npm run build
cp ../resources/map.html android/app/src/main/assets/map.html
cp ../resources/map.html ios/MyApp/map.html

See also resources/README.md.

Web Bundle Development

The WebView runtime is generated from webProject and committed as:

  • src/components/webMapBuild.ts — inline MAP_HTML used by MapView by default
  • resources/map.html — same single-file bundle for native app resources (useNativeMapHtml)
cd webProject
npm install
npm run build

npm run build runs Vite and then webProject/scripts/inlineHtml.mjs, which writes both webMapBuild.ts and resources/map.html.

Contributing

See the contributing guide for local setup and development workflow.

License

MIT