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
Google Places API integration components for location search, autocomplete functionality, and place details. These components provide search capabilities within map contexts.
Map-bound search box component that provides Google Places autocomplete functionality within a map context.
/**
* Map-bound search box component with Google Places integration
*/
class SearchBox extends Component<SearchBoxProps> {
/** Returns the current search bounds */
getBounds(): google.maps.LatLngBounds;
/** Returns the array of selected places */
getPlaces(): google.maps.places.PlaceResult[];
}
interface SearchBoxProps {
/** Position of the control on the map */
controlPosition?: number;
/** Default bounds for biasing search results */
defaultBounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;
/** Controlled bounds for biasing search results */
bounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;
/** Callback when places selection changes */
onPlacesChanged?(): void;
}Usage Example:
import SearchBox from "react-google-maps/lib/components/places/SearchBox";
const MapWithSearch = () => {
const [searchBox, setSearchBox] = useState(null);
const [markers, setMarkers] = useState([]);
const onPlacesChanged = () => {
const places = searchBox.getPlaces();
// Clear existing markers
setMarkers([]);
if (places.length === 0) {
return;
}
// Create markers for each place
const newMarkers = places.map(place => ({
position: {
lat: place.geometry.location.lat(),
lng: place.geometry.location.lng()
},
title: place.name,
place: place
}));
setMarkers(newMarkers);
// Fit map bounds to show all places
const bounds = new google.maps.LatLngBounds();
places.forEach(place => {
if (place.geometry.viewport) {
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
});
// map.fitBounds(bounds);
};
return (
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<SearchBox
ref={ref => setSearchBox(ref)}
bounds={new google.maps.LatLngBounds(
new google.maps.LatLng(37.7049, -122.4794),
new google.maps.LatLng(37.8449, -122.3594)
)}
controlPosition={google.maps.ControlPosition.TOP_LEFT}
onPlacesChanged={onPlacesChanged}
>
<input
type="text"
placeholder="Search for places..."
style={{
boxSizing: 'border-box',
border: '1px solid transparent',
width: '240px',
height: '32px',
marginTop: '27px',
padding: '0 12px',
borderRadius: '3px',
boxShadow: '0 2px 6px rgba(0, 0, 0, 0.3)',
fontSize: '14px',
outline: 'none',
textOverflow: 'ellipsis',
}}
/>
</SearchBox>
{markers.map((marker, index) => (
<Marker
key={index}
position={marker.position}
title={marker.title}
/>
))}
</GoogleMap>
);
};Standalone search box component that works independently of a map context, useful for search forms and location pickers.
/**
* Standalone search box component independent of map context
*/
class StandaloneSearchBox extends Component<StandaloneSearchBoxProps> {
/** Returns the current search bounds */
getBounds(): google.maps.LatLngBounds;
/** Returns the array of selected places */
getPlaces(): google.maps.places.PlaceResult[];
}
interface StandaloneSearchBoxProps {
/** Default bounds for biasing search results */
defaultBounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;
/** Controlled bounds for biasing search results */
bounds?: google.maps.LatLngBounds | google.maps.LatLngBoundsLiteral;
/** Callback when places selection changes */
onPlacesChanged?(): void;
}Usage Example:
import StandaloneSearchBox from "react-google-maps/lib/components/places/StandaloneSearchBox";
const LocationPicker = ({ onLocationSelect }) => {
const [searchBox, setSearchBox] = useState(null);
const [selectedPlace, setSelectedPlace] = useState(null);
const onPlacesChanged = () => {
const places = searchBox.getPlaces();
if (places.length > 0) {
const place = places[0];
const location = {
lat: place.geometry.location.lat(),
lng: place.geometry.location.lng(),
name: place.name,
address: place.formatted_address,
placeId: place.place_id,
types: place.types
};
setSelectedPlace(location);
if (onLocationSelect) {
onLocationSelect(location);
}
}
};
return (
<div style={{ padding: '20px', maxWidth: '400px' }}>
<h3>Select a Location</h3>
<StandaloneSearchBox
ref={ref => setSearchBox(ref)}
bounds={new google.maps.LatLngBounds(
new google.maps.LatLng(37.7049, -122.4794),
new google.maps.LatLng(37.8449, -122.3594)
)}
onPlacesChanged={onPlacesChanged}
>
<input
type="text"
placeholder="Search for a location..."
style={{
width: '100%',
padding: '12px',
fontSize: '16px',
border: '1px solid #ddd',
borderRadius: '4px',
outline: 'none'
}}
/>
</StandaloneSearchBox>
{selectedPlace && (
<div style={{
marginTop: '16px',
padding: '12px',
backgroundColor: '#f5f5f5',
borderRadius: '4px'
}}>
<h4>{selectedPlace.name}</h4>
<p>{selectedPlace.address}</p>
<p>
<strong>Coordinates:</strong> {selectedPlace.lat.toFixed(6)}, {selectedPlace.lng.toFixed(6)}
</p>
<p>
<strong>Types:</strong> {selectedPlace.types.join(', ')}
</p>
</div>
)}
</div>
);
};Places components require the Google Places API to be enabled and the places library to be loaded:
const googleMapURL = `https://maps.googleapis.com/maps/api/js?key=${API_KEY}&libraries=places`;
const MapComponent = withScriptjs(withGoogleMap(() => (
<GoogleMap defaultZoom={10} defaultCenter={{ lat: 37.7749, lng: -122.4194 }}>
<SearchBox>
<input type="text" placeholder="Search..." />
</SearchBox>
</GoogleMap>
)));
<MapComponent
googleMapURL={googleMapURL}
loadingElement={<div style={{ height: "100%" }} />}
containerElement={<div style={{ height: "400px" }} />}
mapElement={<div style={{ height: "100%" }} />}
/>Filter search results by place types:
const RestaurantSearchBox = () => {
const [searchBox, setSearchBox] = useState(null);
const [places, setPlaces] = useState([]);
const onPlacesChanged = () => {
const allPlaces = searchBox.getPlaces();
// Filter for restaurants only
const restaurants = allPlaces.filter(place =>
place.types.includes('restaurant') ||
place.types.includes('food') ||
place.types.includes('meal_takeaway')
);
setPlaces(restaurants);
};
return (
<div>
<StandaloneSearchBox
ref={ref => setSearchBox(ref)}
onPlacesChanged={onPlacesChanged}
>
<input
type="text"
placeholder="Search for restaurants..."
style={{ width: '300px', padding: '8px' }}
/>
</StandaloneSearchBox>
<div style={{ marginTop: '16px' }}>
{places.map((place, index) => (
<div key={index} style={{ marginBottom: '12px', padding: '8px', border: '1px solid #ddd' }}>
<h4>{place.name}</h4>
<p>{place.formatted_address}</p>
<p>Rating: {place.rating || 'No rating'}</p>
<p>Types: {place.types.join(', ')}</p>
</div>
))}
</div>
</div>
);
};Bias search results based on user's current location:
const LocationBiasedSearch = () => {
const [searchBox, setSearchBox] = useState(null);
const [userLocation, setUserLocation] = useState(null);
const [searchBounds, setSearchBounds] = useState(null);
useEffect(() => {
// Get user's current location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
(position) => {
const userPos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
setUserLocation(userPos);
// Create search bounds around user location (5km radius)
const bounds = new google.maps.LatLngBounds();
const center = new google.maps.LatLng(userPos.lat, userPos.lng);
const radius = 0.045; // Approximately 5km
bounds.extend(new google.maps.LatLng(
userPos.lat + radius,
userPos.lng + radius
));
bounds.extend(new google.maps.LatLng(
userPos.lat - radius,
userPos.lng - radius
));
setSearchBounds(bounds);
},
(error) => {
console.error("Geolocation error:", error);
}
);
}
}, []);
return (
<StandaloneSearchBox
ref={ref => setSearchBox(ref)}
bounds={searchBounds}
onPlacesChanged={() => {
const places = searchBox.getPlaces();
console.log("Places near you:", places);
}}
>
<input
type="text"
placeholder={userLocation ? "Search near your location..." : "Search..."}
style={{ width: '300px', padding: '8px' }}
/>
</StandaloneSearchBox>
);
};Get detailed place information using the Places API:
const DetailedPlaceSearch = () => {
const [searchBox, setSearchBox] = useState(null);
const [placeDetails, setPlaceDetails] = useState(null);
const onPlacesChanged = () => {
const places = searchBox.getPlaces();
if (places.length > 0) {
const place = places[0];
// Get additional place details
const service = new google.maps.places.PlacesService(
document.createElement('div')
);
service.getDetails({
placeId: place.place_id,
fields: [
'name', 'formatted_address', 'geometry', 'rating',
'photos', 'opening_hours', 'formatted_phone_number',
'website', 'reviews', 'price_level'
]
}, (detailedPlace, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK) {
setPlaceDetails(detailedPlace);
}
});
}
};
return (
<div>
<StandaloneSearchBox
ref={ref => setSearchBox(ref)}
onPlacesChanged={onPlacesChanged}
>
<input
type="text"
placeholder="Search for detailed place info..."
style={{ width: '400px', padding: '12px' }}
/>
</StandaloneSearchBox>
{placeDetails && (
<div style={{ marginTop: '20px', padding: '16px', border: '1px solid #ddd' }}>
<h2>{placeDetails.name}</h2>
<p><strong>Address:</strong> {placeDetails.formatted_address}</p>
<p><strong>Rating:</strong> {placeDetails.rating}/5</p>
<p><strong>Phone:</strong> {placeDetails.formatted_phone_number}</p>
{placeDetails.website && (
<p><strong>Website:</strong> <a href={placeDetails.website} target="_blank" rel="noopener noreferrer">{placeDetails.website}</a></p>
)}
{placeDetails.opening_hours && (
<div>
<strong>Hours:</strong>
<ul>
{placeDetails.opening_hours.weekday_text.map((day, index) => (
<li key={index}>{day}</li>
))}
</ul>
</div>
)}
</div>
)}
</div>
);
};Install with Tessl CLI
npx tessl i tessl/npm-react-google-maps