React components rendered as children of GoogleMapReact are automatically positioned on the map using lat/lng coordinates. The component provides an internal hover system and passes special props to child components.
Required and automatic props for components rendered on the map.
/**
* Props interface for components rendered as children of GoogleMapReact
*/
interface MapChildProps {
// Required positioning props
lat: number;
lng: number;
// Automatically injected props
$hover?: boolean;
// Custom props (any additional props you want to pass)
[key: string]: any;
}Basic Usage:
// Simple marker component
const Marker = ({ text, $hover }) => (
<div style={{
backgroundColor: $hover ? 'red' : 'blue',
color: 'white',
padding: '4px 8px',
borderRadius: '4px',
transform: 'translate(-50%, -50%)' // Center the marker
}}>
{text}
</div>
);
// Use in map
<GoogleMapReact
defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
defaultZoom={10}
>
<Marker
lat={37.7749}
lng={-122.4194}
text="San Francisco"
/>
</GoogleMapReact>GoogleMapReact includes an internal hover detection system that automatically manages hover states for child components.
interface HoverSystemProps {
// Distance function for hover detection
distanceToMouse?: (
pt: { x: number; y: number },
mousePos: { x: number; y: number },
markerProps: any
) => number;
// Maximum distance for hover detection (pixels)
hoverDistance?: number;
// Whether to debounce hover calculations
debounced?: boolean;
}Advanced Hover Example:
const InteractiveMarker = ({ text, $hover, onClick }) => (
<div
style={{
backgroundColor: $hover ? '#ff4444' : '#4444ff',
color: 'white',
padding: '8px 12px',
borderRadius: '8px',
cursor: 'pointer',
transform: 'translate(-50%, -50%)',
transition: 'all 0.2s ease',
boxShadow: $hover ? '0 4px 8px rgba(0,0,0,0.3)' : '0 2px 4px rgba(0,0,0,0.2)',
fontSize: $hover ? '14px' : '12px'
}}
onClick={onClick}
>
{text}
</div>
);
<GoogleMapReact
defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
defaultZoom={10}
hoverDistance={20}
debounced={true}
onChildClick={(childKey, childProps) => {
console.log('Marker clicked:', childProps.text);
}}
>
<InteractiveMarker
key="sf-marker"
lat={37.7749}
lng={-122.4194}
text="Click me!"
onClick={() => alert('Marker clicked!')}
/>
</GoogleMapReact>Guidelines for properly positioning child components on the map.
interface PositioningStyles {
position?: 'absolute' | 'relative';
transform?: string;
transformOrigin?: string;
left?: string | number;
top?: string | number;
}Positioning Examples:
// Centered marker (most common)
const CenteredMarker = ({ children }) => (
<div style={{
position: 'absolute',
transform: 'translate(-50%, -50%)',
transformOrigin: 'center center'
}}>
{children}
</div>
);
// Bottom-centered marker (pin style)
const PinMarker = ({ children }) => (
<div style={{
position: 'absolute',
transform: 'translate(-50%, -100%)',
transformOrigin: 'center bottom'
}}>
{children}
</div>
);
// Top-left positioned marker
const TopLeftMarker = ({ children }) => (
<div style={{
position: 'absolute',
transform: 'translate(0, 0)',
transformOrigin: 'top left'
}}>
{children}
</div>
);
// Usage
<GoogleMapReact defaultCenter={{ lat: 37.7749, lng: -122.4194 }} defaultZoom={10}>
<CenteredMarker lat={37.7749} lng={-122.4194}>
<div style={{ backgroundColor: 'red', width: 20, height: 20, borderRadius: '50%' }} />
</CenteredMarker>
<PinMarker lat={37.7849} lng={-122.4094}>
<div style={{ backgroundColor: 'blue', width: 0, height: 0, borderLeft: '10px solid transparent', borderRight: '10px solid transparent', borderTop: '20px solid blue' }} />
</PinMarker>
</GoogleMapReact>Create markers dynamically from data arrays.
function DynamicMarkers({ locations }) {
return (
<GoogleMapReact
defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
defaultZoom={10}
>
{locations.map((location, index) => (
<Marker
key={location.id || index}
lat={location.lat}
lng={location.lng}
text={location.name}
type={location.type}
/>
))}
</GoogleMapReact>
);
}
// Usage
const locations = [
{ id: 1, lat: 37.7749, lng: -122.4194, name: 'San Francisco', type: 'city' },
{ id: 2, lat: 37.7849, lng: -122.4094, name: 'North Beach', type: 'neighborhood' },
{ id: 3, lat: 37.7649, lng: -122.4294, name: 'Mission', type: 'neighborhood' }
];
<DynamicMarkers locations={locations} />Show/hide markers based on zoom level or other conditions.
function ZoomDependentMarkers({ zoom, markers }) {
return (
<GoogleMapReact
zoom={zoom}
defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
onChange={({ zoom }) => setZoom(zoom)}
>
{markers.map(marker => {
// Only show detailed markers at high zoom levels
if (marker.type === 'detailed' && zoom < 12) {
return null;
}
// Only show overview markers at low zoom levels
if (marker.type === 'overview' && zoom > 8) {
return null;
}
return (
<Marker
key={marker.id}
lat={marker.lat}
lng={marker.lng}
text={marker.name}
/>
);
})}
</GoogleMapReact>
);
}Implement custom hover detection logic.
function CustomHoverMap() {
const customDistanceFunction = (pt, mousePos, markerProps) => {
// Custom distance calculation - larger hover area for important markers
const baseDistance = Math.sqrt(
Math.pow(pt.x - mousePos.x, 2) + Math.pow(pt.y - mousePos.y, 2)
);
// Increase hover distance for VIP markers
return markerProps.isVIP ? baseDistance * 0.5 : baseDistance;
};
return (
<GoogleMapReact
defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
defaultZoom={10}
distanceToMouse={customDistanceFunction}
hoverDistance={30}
>
<Marker lat={37.7749} lng={-122.4194} text="VIP Location" isVIP={true} />
<Marker lat={37.7849} lng={-122.4094} text="Regular Location" isVIP={false} />
</GoogleMapReact>
);
}Handle various mouse events on child components.
function EventHandlingMap() {
const handleChildMouseEnter = (childKey, childProps) => {
console.log('Mouse entered:', childProps.text);
};
const handleChildMouseLeave = (childKey, childProps) => {
console.log('Mouse left:', childProps.text);
};
const handleChildClick = (childKey, childProps) => {
console.log('Clicked:', childProps.text);
};
const handleChildMouseDown = (childKey, childProps) => {
console.log('Mouse down:', childProps.text);
};
const handleChildMouseUp = (childKey, childProps) => {
console.log('Mouse up:', childProps.text);
};
return (
<GoogleMapReact
defaultCenter={{ lat: 37.7749, lng: -122.4194 }}
defaultZoom={10}
onChildMouseEnter={handleChildMouseEnter}
onChildMouseLeave={handleChildMouseLeave}
onChildClick={handleChildClick}
onChildMouseDown={handleChildMouseDown}
onChildMouseUp={handleChildMouseUp}
>
<InteractiveMarker
lat={37.7749}
lng={-122.4194}
text="Interactive Marker"
/>
</GoogleMapReact>
);
}Use React.memo and stable keys to optimize performance with many markers.
const Marker = React.memo(({ lat, lng, text, $hover }) => (
<div style={{
backgroundColor: $hover ? 'red' : 'blue',
color: 'white',
padding: '4px 8px',
borderRadius: '4px',
transform: 'translate(-50%, -50%)'
}}>
{text}
</div>
));
// Use stable keys and avoid inline object creation
function OptimizedMarkers({ locations }) {
return (
<GoogleMapReact defaultCenter={{ lat: 37.7749, lng: -122.4194 }} defaultZoom={10}>
{locations.map(location => (
<Marker
key={location.id} // Stable key
lat={location.lat}
lng={location.lng}
text={location.name}
/>
))}
</GoogleMapReact>
);
}