React.js Google Maps integration component library providing comprehensive Google Maps functionality through React components
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Third-party addon components that extend Google Maps functionality with enhanced features like marker clustering, custom info boxes, and labeled markers. These components require additional dependencies.
Enhanced info window component with advanced styling and positioning options. Requires the google-maps-infobox package.
/**
* Enhanced info window with advanced styling options
* Requires: npm install google-maps-infobox
*/
class InfoBox extends Component<InfoBoxProps> {}
interface InfoBoxProps {
// Default props
defaultOptions?: InfoBoxOptions;
defaultPosition?: google.maps.LatLng;
defaultVisible?: boolean;
defaultZIndex?: number;
// Controlled props
options?: InfoBoxOptions;
position?: google.maps.LatLng;
visible?: boolean;
zIndex?: number;
// Event handlers
onCloseClick?(): void;
onContentChanged?(): void;
onDomReady?(): void;
onPositionChanged?(): void;
onZindexChanged?(): void;
}Usage Example:
import InfoBox from "react-google-maps/lib/components/addons/InfoBox";
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<Marker position={{ lat: 37.7749, lng: -122.4194 }} />
<InfoBox
position={{ lat: 37.7749, lng: -122.4194 }}
options={{
content: `
<div style="background: white; padding: 12px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.2);">
<h3 style="margin: 0 0 8px 0;">San Francisco</h3>
<p style="margin: 0;">The City by the Bay</p>
</div>
`,
disableAutoPan: false,
maxWidth: 0,
pixelOffset: { width: -140, height: 0 },
zIndex: null,
boxStyle: {
background: "url('tipbox.gif') no-repeat",
opacity: 0.75,
width: "280px"
},
closeBoxMargin: "10px 2px 2px 2px",
closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif",
infoBoxClearance: { width: 50, height: 200 }
}}
onCloseClick={() => {
console.log("InfoBox closed");
}}
/>
</GoogleMap>Component for clustering markers when they are close together at low zoom levels. Requires the marker-clusterer-plus package.
/**
* Marker clustering component for managing large numbers of markers
* Requires: npm install marker-clusterer-plus
*/
class MarkerClusterer extends Component<MarkerClustererProps> {}
interface MarkerClustererProps {
// Default clustering options
defaultAverageCenter?: boolean;
defaultBatchSizeIE?: number;
defaultBatchSize?: number;
defaultCalculator?: Calculator;
defaultClusterClass?: string;
defaultEnableRetinaIcons?: boolean;
defaultGridSize?: number;
defaultIgnoreHidden?: boolean;
defaultImageExtension?: string;
defaultImagePath?: string;
defaultImageSizes?: number[];
defaultMaxZoom?: number;
defaultMinimumClusterSize?: number;
defaultStyles?: ClusterIconStyle[];
defaultTitle?: string;
defaultZoomOnClick?: boolean;
// Controlled clustering options
averageCenter?: boolean;
batchSizeIE?: number;
batchSize?: number;
calculator?: Calculator;
clusterClass?: string;
enableRetinaIcons?: boolean;
gridSize?: number;
ignoreHidden?: boolean;
imageExtension?: string;
imagePath?: string;
imageSizes?: number[];
maxZoom?: number;
minimumClusterSize?: number;
styles?: ClusterIconStyle[];
title?: string;
zoomOnClick?: boolean;
// Event handlers
onClick?(cluster: Cluster): void;
onClusteringBegin?(mc: MarkerClusterer): void;
onClusteringEnd?(mc: MarkerClusterer): void;
onMouseOut?(c: Cluster): void;
onMouseOver?(c: Cluster): void;
}Usage Example:
import MarkerClusterer from "react-google-maps/lib/components/addons/MarkerClusterer";
const ClusteredMarkers = () => {
const [markers] = useState([
{ lat: 37.7749, lng: -122.4194, id: 1 },
{ lat: 37.7849, lng: -122.4094, id: 2 },
{ lat: 37.7649, lng: -122.4294, id: 3 },
// ... many more markers
]);
return (
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<MarkerClusterer
averageCenter={true}
enableRetinaIcons={true}
gridSize={60}
maxZoom={15}
minimumClusterSize={2}
styles={[
{
textColor: 'white',
url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m1.png',
height: 53,
width: 53
},
{
textColor: 'white',
url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m2.png',
height: 56,
width: 56
},
{
textColor: 'white',
url: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m3.png',
height: 66,
width: 66
}
]}
onClick={(cluster) => {
console.log(`Cluster clicked with ${cluster.getMarkers().length} markers`);
}}
onClusteringEnd={(markerClusterer) => {
console.log(`Clustering complete: ${markerClusterer.getClusters().length} clusters`);
}}
>
{markers.map((marker) => (
<Marker
key={marker.id}
position={{ lat: marker.lat, lng: marker.lng }}
title={`Marker ${marker.id}`}
/>
))}
</MarkerClusterer>
</GoogleMap>
);
};Enhanced marker component with custom label styling. Requires the markerwithlabel package and extends the standard Marker props.
/**
* Marker with custom label styling
* Requires: npm install markerwithlabel
* Extends MarkerProps with additional label properties
*/
class MarkerWithLabel extends Component<MarkerProps> {}
// Extends MarkerProps with these additional properties:
interface MarkerLabelProps extends MarkerProps {
/** Custom label class for styling */
labelClass?: string;
/** Anchor point for the label */
labelAnchor?: google.maps.Point;
/** Text content of the label */
labelContent?: string;
/** Inline styles for the label */
labelStyle?: CSSStyleDeclaration;
/** Callback when marker with label functionality is ready */
markerWithLabel?(): void;
}Usage Example:
import MarkerWithLabel from "react-google-maps/lib/components/addons/MarkerWithLabel";
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<MarkerWithLabel
position={{ lat: 37.7749, lng: -122.4194 }}
labelAnchor={new google.maps.Point(0, 0)}
labelContent="San Francisco"
labelStyle={{
backgroundColor: "yellow",
fontSize: "14px",
padding: "4px",
borderRadius: "4px",
border: "1px solid #333"
}}
icon={{
url: "https://maps.google.com/mapfiles/ms/icons/blue-dot.png"
}}
onClick={() => {
console.log("Labeled marker clicked");
}}
/>
<MarkerWithLabel
position={{ lat: 37.7649, lng: -122.4294 }}
labelContent="Custom Location"
labelClass="custom-label"
labelAnchor={new google.maps.Point(30, 0)}
icon={{
url: "https://maps.google.com/mapfiles/ms/icons/red-dot.png"
}}
/>
</GoogleMap>Each addon requires its corresponding npm package:
# For InfoBox
npm install google-maps-infobox
# For MarkerClusterer
npm install marker-clusterer-plus
# For MarkerWithLabel
npm install markerwithlabel
# Install all addons
npm install google-maps-infobox marker-clusterer-plus markerwithlabelAddon components must be imported directly from their specific paths:
// Correct imports for addons
import InfoBox from "react-google-maps/lib/components/addons/InfoBox";
import MarkerClusterer from "react-google-maps/lib/components/addons/MarkerClusterer";
import MarkerWithLabel from "react-google-maps/lib/components/addons/MarkerWithLabel";
// These will NOT work - addons are not in main exports
import { InfoBox, MarkerClusterer, MarkerWithLabel } from "react-google-maps"; // ❌const AdvancedMarkerMap = () => {
const [selectedMarker, setSelectedMarker] = useState(null);
const [markers] = useState(/* large array of markers */);
return (
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<MarkerClusterer
onClick={(cluster) => {
// Zoom into cluster
const bounds = new google.maps.LatLngBounds();
cluster.getMarkers().forEach(marker => {
bounds.extend(marker.getPosition());
});
map.fitBounds(bounds);
}}
>
{markers.map((marker) => (
<Marker
key={marker.id}
position={marker.position}
onClick={() => setSelectedMarker(marker)}
/>
))}
</MarkerClusterer>
{selectedMarker && (
<InfoBox
position={selectedMarker.position}
options={{
content: `
<div class="custom-infobox">
<h3>${selectedMarker.title}</h3>
<p>${selectedMarker.description}</p>
<button onclick="closeInfoBox()">Close</button>
</div>
`
}}
onCloseClick={() => setSelectedMarker(null)}
/>
)}
</GoogleMap>
);
};const customClusterStyles = [
{
textColor: 'white',
textSize: 11,
url: 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40">
<circle cx="20" cy="20" r="18" fill="#ff6b6b" stroke="#fff" stroke-width="2"/>
</svg>
`),
height: 40,
width: 40
},
{
textColor: 'white',
textSize: 12,
url: 'data:image/svg+xml;charset=UTF-8,' + encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
<circle cx="25" cy="25" r="23" fill="#4ecdc4" stroke="#fff" stroke-width="2"/>
</svg>
`),
height: 50,
width: 50
}
];
<MarkerClusterer
styles={customClusterStyles}
calculator={(markers, numStyles) => {
const count = markers.length;
let index = 0;
if (count > 10) index = 1;
if (count > 100) index = 2;
return { text: count, index: index };
}}
>
{/* markers */}
</MarkerClusterer>Install with Tessl CLI
npx tessl i tessl/npm-react-google-maps