Skip to main content
The LocationPuck component renders a native puck on the map that shows the device’s current location. This is the modern, recommended approach for displaying user location.

Basic Usage

import { MapView, Camera, LocationPuck } from '@rnmapbox/maps';

<MapView>
  <Camera followUserLocation />
  <LocationPuck visible={true} />
</MapView>

Props

androidRenderMode
'normal' | 'compass' | 'gps'
Deprecated: Use puckBearing for bearing source and bearingImage for custom images.Android render mode:
  • normal: Simple circle
  • compass: Triangle with heading
  • gps: Large arrow
Platform: Android only
puckBearing
'heading' | 'course'
Determines the bearing source for puck orientation:
  • heading: Orients the puck to match the direction the device is facing (compass direction)
  • course: Orients the puck to match the direction the device is moving (movement direction)
<LocationPuck 
  puckBearing="heading"
  puckBearingEnabled={true}
/>
puckBearingEnabled
boolean
Whether the puck rotates to track the bearing source specified in puckBearing.
<LocationPuck puckBearingEnabled={true} />
iosShowsUserHeadingIndicator
boolean
Deprecated: Use puckBearingEnabled={true} puckBearing="heading" instead.iOS only. A Boolean value indicating whether the user location annotation displays a permanent heading indicator.Platform: iOS only
topImage
string
The name of the image to use as the top layer for the location indicator. The image must be defined in an Images component.
<Images images={{ customTop: require('./assets/top.png') }}>
  <LocationPuck topImage="customTop" />
</Images>
bearingImage
string
The name of the image to use as the middle layer for the location indicator. The image must be defined in an Images component.Used to display directional information (heading/course).
<Images images={{ arrow: require('./assets/arrow.png') }}>
  <LocationPuck bearingImage="arrow" />
</Images>
shadowImage
string
The name of the image to use as the background for the location indicator. The image must be defined in an Images component.
<Images images={{ shadow: require('./assets/shadow.png') }}>
  <LocationPuck shadowImage="shadow" />
</Images>
scale
number | Expression
The size of the images, as a scale factor applied to the size of the specified image. Supports Mapbox expressions based on zoom level.
// Static scale
<LocationPuck scale={2.0} />

// Dynamic scale based on zoom
<LocationPuck 
  scale={[
    'interpolate',
    ['linear'],
    ['zoom'],
    10.0, 1.0,
    20.0, 4.0
  ]}
/>
pulsing
PulsingConfig | 'default'
Configuration for the sonar-like pulsing circle animation shown around the 2D puck.Use 'default' for default pulsing animation, or provide a configuration object:
<LocationPuck 
  pulsing={{
    isEnabled: true,
    color: '#007AFF',
    radius: 'accuracy'
  }}
/>
visible
boolean
default:"true"
Whether the location icon is visible on the map.

Types

PulsingConfig

isEnabled
boolean
Flag determining whether the pulsing circle animation is enabled.
color
number | ColorValue
The color of the pulsing circle. Can be a processed color number or React Native ColorValue.
color: '#007AFF'
color: 'rgba(0, 122, 255, 0.3)'
radius
'accuracy' | number
Circle radius configuration for the pulsing circle animation:
  • 'accuracy': Pulsing circle animates with the horizontalAccuracy from the latest puck location
  • number: Pulsing circle animates with a constant radius value
radius: 'accuracy'  // Dynamic based on GPS accuracy
radius: 50          // Fixed 50 meter radius

Examples

Basic Location Puck

import { MapView, Camera, LocationPuck } from '@rnmapbox/maps';

function MyMap() {
  return (
    <MapView>
      <Camera followUserLocation />
      <LocationPuck visible={true} />
    </MapView>
  );
}

With Heading Indicator

import { MapView, LocationPuck } from '@rnmapbox/maps';

function MyMap() {
  return (
    <MapView>
      <LocationPuck 
        puckBearing="heading"
        puckBearingEnabled={true}
        visible={true}
      />
    </MapView>
  );
}

With Course Tracking

<LocationPuck 
  puckBearing="course"
  puckBearingEnabled={true}
  visible={true}
/>

With Default Pulsing

<LocationPuck 
  pulsing="default"
  visible={true}
/>

With Custom Pulsing

<LocationPuck 
  pulsing={{
    isEnabled: true,
    color: '#007AFF',
    radius: 'accuracy'
  }}
  visible={true}
/>

With Custom Images

import { MapView, LocationPuck, Images } from '@rnmapbox/maps';

function MyMap() {
  return (
    <MapView>
      <Images
        images={{
          customPuck: require('./assets/puck.png'),
          customArrow: require('./assets/arrow.png'),
          customShadow: require('./assets/shadow.png'),
        }}
      >
        <LocationPuck 
          topImage="customPuck"
          bearingImage="customArrow"
          shadowImage="customShadow"
          scale={2.0}
          puckBearing="heading"
          puckBearingEnabled={true}
        />
      </Images>
    </MapView>
  );
}

With Zoom-based Scaling

<LocationPuck 
  scale={[
    'interpolate',
    ['linear'],
    ['zoom'],
    10.0, 1.0,   // At zoom 10, scale is 1x
    20.0, 4.0    // At zoom 20, scale is 4x
  ]}
/>

With Fixed Pulse Radius

<LocationPuck 
  pulsing={{
    isEnabled: true,
    color: 'rgba(51, 181, 229, 0.3)',
    radius: 100  // Fixed 100 meter radius
  }}
/>

Migration from UserLocation

If you’re using UserLocation with renderMode={UserLocationRenderMode.Native}, migrate to LocationPuck:
// Old approach (deprecated)
<UserLocation 
  renderMode={UserLocationRenderMode.Native}
  showsUserHeadingIndicator={true}
/>

// New approach
<LocationPuck 
  puckBearingEnabled={true}
  puckBearing="heading"
/>

See Also

Build docs developers (and LLMs) love