Send feedback
React Google Maps Library - Place Autocomplete
Stay organized with collections
Save and categorize content based on your preferences.
This example shows using the Places Autocomplete widget to update a map and
marker in
a React application. It uses the
vis.gl/react-google-maps open
source library.The
vis.gl/react-google-maps library
is a collection of React components and hooks for the Google Maps JavaScript
API.
Important: The
vis.gl/react-google-maps library
is offered using an open source license. It is not governed by the Google Maps
Platform Support Technical Support Services Guidelines, the SLA, or the
Deprecation Policy (however, any Google Maps Platform services used by the
library remain subject to the Google Maps Platform Terms of Service). If you
find a bug, or have a feature request, file an issue on
GitHub .
TypeScript
import React , { useState , useEffect , useRef } from 'react' ;
import { createRoot } from 'react-dom/client' ;
import {
APIProvider ,
ControlPosition ,
MapControl ,
AdvancedMarker ,
Map ,
useMap ,
useMapsLibrary ,
useAdvancedMarkerRef ,
AdvancedMarkerRef
} from '@vis.gl/react-google-maps' ;
const API_KEY =
globalThis . GOOGLE_MAPS_API_KEY ?? ( "YOUR_API_KEY" );
const App = () = > {
const [ selectedPlace , setSelectedPlace ] =
useState<google . maps . places . PlaceResult | null >( null );
const [ markerRef , marker ] = useAdvancedMarkerRef ();
return (
<APIProvider
apiKey = { API_KEY }
solutionChannel = 'GMP_devsite_samples_v3_rgmautocomplete' >
<Map
mapId = { 'bf51a910020fa25a' }
defaultZoom = { 3 }
defaultCenter = {{ lat: 22.54992, lng: 0 }}
gestureHandling = { 'greedy' }
disableDefaultUI = { true }
>
<AdvancedMarker ref = { markerRef } position = { null } / >
</Map >
<MapControl position = { ControlPosition . TOP } >
<div className = "autocomplete-control" >
<PlaceAutocomplete onPlaceSelect = { setSelectedPlace } / >
</div >
</MapControl >
<MapHandler place = { selectedPlace } marker = { marker } / >
</APIProvider >
);
};
interface MapHandlerProps {
place : google . maps . places . PlaceResult | null ;
marker : google . maps . marker . AdvancedMarkerElement | null ;
}
const MapHandler = ({ place , marker } : MapHandlerProps ) = > {
const map = useMap ();
useEffect (() = > {
if ( ! map || ! place || ! marker ) return ;
if ( place . geometry ? . viewport ) {
map . fitBounds ( place . geometry ? . viewport );
}
marker . position = place . geometry ? . location ;
}, [ map , place , marker ]);
return null ;
};
interface PlaceAutocompleteProps {
onPlaceSelect : ( place : google . maps . places . PlaceResult | null ) = > void ;
}
const PlaceAutocomplete = ({ onPlaceSelect } : PlaceAutocompleteProps ) = > {
const [ placeAutocomplete , setPlaceAutocomplete ] =
useState<google . maps . places . Autocomplete | null >( null );
const inputRef = useRef<HTMLInputElement> ( null );
const places = useMapsLibrary ( 'places' );
useEffect (() = > {
if ( ! places || ! inputRef . current ) return ;
const options = {
fields : [ 'geometry' , 'name' , 'formatted_address' ]
};
setPlaceAutocomplete ( new places . Autocomplete ( inputRef . current , options ));
}, [ places ]);
useEffect (() = > {
if ( ! placeAutocomplete ) return ;
placeAutocomplete . addListener ( 'place_changed' , () = > {
onPlaceSelect ( placeAutocomplete . getPlace ());
});
}, [ onPlaceSelect , placeAutocomplete ]);
return (
<div className = "autocomplete-container" >
<input ref = { inputRef } / >
</div >
);
};
const root = createRoot ( document . getElementById ( 'app' ) ! );
root . render ( <App / >);
export default App ;
Note: Read the guide on using TypeScript and Google Maps.
JavaScript
import React , { useState , useEffect , useRef } from "react" ;
import { createRoot } from "react-dom/client" ;
import {
APIProvider ,
ControlPosition ,
MapControl ,
AdvancedMarker ,
Map ,
useMap ,
useMapsLibrary ,
useAdvancedMarkerRef ,
} from "@vis.gl/react-google-maps" ;
const API_KEY = globalThis . GOOGLE_MAPS_API_KEY ?? "YOUR_API_KEY" ;
const App = () = > {
const [ selectedPlace , setSelectedPlace ] = useState ( null );
const [ markerRef , marker ] = useAdvancedMarkerRef ();
return (
<APIProvider
apiKey = { API_KEY }
solutionChannel = "GMP_devsite_samples_v3_rgmautocomplete"
>
<Map
mapId = { "bf51a910020fa25a" }
defaultZoom = { 3 }
defaultCenter = {{ lat: 22.54992, lng: 0 }}
gestureHandling = { "greedy" }
disableDefaultUI = { true }
>
<AdvancedMarker ref = { markerRef } position = { null } / >
</Map >
<MapControl position = { ControlPosition . TOP } >
<div className = "autocomplete-control" >
<PlaceAutocomplete onPlaceSelect = { setSelectedPlace } / >
</div >
</MapControl >
<MapHandler place = { selectedPlace } marker = { marker } / >
</APIProvider >
);
};
const MapHandler = ({ place , marker }) = > {
const map = useMap ();
useEffect (() = > {
if ( ! map || ! place || ! marker ) return ;
if ( place . geometry ? . viewport ) {
map . fitBounds ( place . geometry ? . viewport );
}
marker . position = place . geometry ? . location ;
}, [ map , place , marker ]);
return null ;
};
const PlaceAutocomplete = ({ onPlaceSelect }) = > {
const [ placeAutocomplete , setPlaceAutocomplete ] = useState ( null );
const inputRef = useRef ( null );
const places = useMapsLibrary ( "places" );
useEffect (() = > {
if ( ! places || ! inputRef . current ) return ;
const options = {
fields : [ "geometry" , "name" , "formatted_address" ],
};
setPlaceAutocomplete ( new places . Autocomplete ( inputRef . current , options ));
}, [ places ]);
useEffect (() = > {
if ( ! placeAutocomplete ) return ;
placeAutocomplete . addListener ( "place_changed" , () = > {
onPlaceSelect ( placeAutocomplete . getPlace ());
});
}, [ onPlaceSelect , placeAutocomplete ]);
return (
<div className = "autocomplete-container" >
<input ref = { inputRef } / >
</div >
);
};
const root = createRoot ( document . getElementById ( "app" ));
root . render ( <App / >);
export default App ;
Note: The JavaScript is compiled from the TypeScript snippet.
CSS
body {
margin : 0 ;
font-family : sans-serif ;
}
# app {
width : 100 vw ;
height : 100 vh ;
}
. autocomplete-container input ,
. autocomplete-control {
box-sizing : border-box ;
}
. autocomplete-control {
margin : 24 px ;
background : #fff ;
}
. autocomplete-container {
width : 300 px ;
}
. autocomplete-container input {
width : 100 % ;
height : 40 px ;
padding : 0 12 px ;
font-size : 18 px ;
}
. autocomplete-container . custom-list {
width : 100 % ;
list-style : none ;
padding : 0 ;
margin : 0 ;
}
. autocomplete-container . custom-list-item {
padding : 8 px ;
}
. autocomplete-container . custom-list-item : hover {
background : lightgrey ;
cursor : pointer ;
}
HTML
<html>
<head>
<title>React Google Maps - Autocomplete</title>
<link rel="stylesheet" type="text/css" href="./style.css" />
</head>
<body>
<div id="app"></div>
<script type="module" src="./index"></script>
</body>
</html>
Try Sample
Clone Sample
Git and Node.js are required to run this sample locally. Follow these instructions to install Node.js and NPM. The following commands clone, install dependencies and start the sample application.
git clone - b sample - rgm - autocomplete https : //github.com/googlemaps/js-samples.git
cd js - samples
npm i
npm start
Other samples can be tried by switching to any branch beginning with sample-SAMPLE_NAME
.
git checkout sample - SAMPLE_NAME
npm i
npm start
Send feedback
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License , and code samples are licensed under the Apache 2.0 License . For details, see the Google Developers Site Policies . Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2025-08-20 UTC.
Need to tell us more?
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-20 UTC."],[[["\u003cp\u003eThis example demonstrates the integration of the Places Autocomplete widget within a React application to dynamically update a map and marker.\u003c/p\u003e\n"],["\u003cp\u003eIt leverages the \u003ccode\u003evis.gl/react-google-maps\u003c/code\u003e library, providing React components for interacting with the Google Maps JavaScript API.\u003c/p\u003e\n"],["\u003cp\u003eThe provided code snippets include TypeScript, JavaScript, CSS, and HTML to showcase the complete implementation.\u003c/p\u003e\n"],["\u003cp\u003eAlthough the \u003ccode\u003evis.gl/react-google-maps\u003c/code\u003e library is open source and not covered by Google Maps Platform support, the underlying Google Maps services used are still subject to the Google Maps Platform Terms of Service.\u003c/p\u003e\n"]]],[],null,["This example shows using the Places Autocomplete widget to update a map and\nmarker in\na React application. It uses the\n[vis.gl/react-google-maps](https://visgl.github.io/react-google-maps/) open\nsource library.The\n[vis.gl/react-google-maps](https://visgl.github.io/react-google-maps/) library\nis a collection of React components and hooks for the Google Maps JavaScript\nAPI.\n**Important:** The [vis.gl/react-google-maps](https://visgl.github.io/react-google-maps/) library is offered using an open source license. It is not governed by the Google Maps Platform Support Technical Support Services Guidelines, the SLA, or the Deprecation Policy (however, any Google Maps Platform services used by the library remain subject to the Google Maps Platform Terms of Service). If you find a bug, or have a feature request, file an issue on [GitHub](https://github.com/visgl/react-google-maps/issues) . \n\nTypeScript \n\n```jsx\nimport React, { useState, useEffect, useRef } from 'react';\nimport { createRoot } from 'react-dom/client';\nimport {\n APIProvider,\n ControlPosition,\n MapControl,\n AdvancedMarker,\n Map,\n useMap,\n useMapsLibrary,\n useAdvancedMarkerRef,\n AdvancedMarkerRef\n} from '@vis.gl/react-google-maps';\n\nconst API_KEY =\n globalThis.GOOGLE_MAPS_API_KEY ?? (\"YOUR_API_KEY\");\n\nconst App = () =\u003e {\n const [selectedPlace, setSelectedPlace] =\n useState\u003cgoogle.maps.places.PlaceResult | null\u003e(null);\n const [markerRef, marker] = useAdvancedMarkerRef();\n\n return (\n \u003cAPIProvider\n apiKey={API_KEY}\n solutionChannel='GMP_devsite_samples_v3_rgmautocomplete'\u003e\n \u003cMap\n mapId={'bf51a910020fa25a'}\n defaultZoom={3}\n defaultCenter={{ lat: 22.54992, lng: 0 }}\n gestureHandling={'greedy'}\n disableDefaultUI={true}\n \u003e\n \u003cAdvancedMarker ref={markerRef} position={null} /\u003e\n \u003c/Map\u003e\n \u003cMapControl position={ControlPosition.TOP}\u003e\n \u003cdiv className=\"autocomplete-control\"\u003e\n \u003cPlaceAutocomplete onPlaceSelect={setSelectedPlace} /\u003e\n \u003c/div\u003e\n \u003c/MapControl\u003e\n \u003cMapHandler place={selectedPlace} marker={marker} /\u003e\n \u003c/APIProvider\u003e\n );\n};\n\ninterface MapHandlerProps {\n place: google.maps.places.PlaceResult | null;\n marker: google.maps.marker.AdvancedMarkerElement | null;\n}\n\nconst MapHandler = ({ place, marker }: MapHandlerProps) =\u003e {\n const map = useMap();\n\n useEffect(() =\u003e {\n if (!map || !place || !marker) return;\n\n if (place.geometry?.viewport) {\n map.fitBounds(place.geometry?.viewport);\n }\n marker.position = place.geometry?.location;\n }, [map, place, marker]);\n\n return null;\n};\n\ninterface PlaceAutocompleteProps {\n onPlaceSelect: (place: google.maps.places.PlaceResult | null) =\u003e void;\n}\n\nconst PlaceAutocomplete = ({ onPlaceSelect }: PlaceAutocompleteProps) =\u003e {\n const [placeAutocomplete, setPlaceAutocomplete] =\n useState\u003cgoogle.maps.places.Autocomplete | null\u003e(null);\n const inputRef = useRef\u003cHTMLInputElement\u003e(null);\n const places = useMapsLibrary('places');\n\n useEffect(() =\u003e {\n if (!places || !inputRef.current) return;\n\n const options = {\n fields: ['geometry', 'name', 'formatted_address']\n };\n\n setPlaceAutocomplete(new places.Autocomplete(inputRef.current, options));\n }, [places]);\n\n useEffect(() =\u003e {\n if (!placeAutocomplete) return;\n\n placeAutocomplete.addListener('place_changed', () =\u003e {\n onPlaceSelect(placeAutocomplete.getPlace());\n });\n }, [onPlaceSelect, placeAutocomplete]);\n\n return (\n \u003cdiv className=\"autocomplete-container\"\u003e\n \u003cinput ref={inputRef} /\u003e\n \u003c/div\u003e\n );\n};\n\nconst root = createRoot(document.getElementById('app')!);\nroot.render(\u003cApp /\u003e);\n\nexport default App;https://github.com/googlemaps/js-samples/blob/2683f7366fb27829401945d2a7e27d77ed2df8e5/samples/rgm-autocomplete/index.tsx#L17-L120\n```\n| **Note:** Read the [guide](/maps/documentation/javascript/using-typescript) on using TypeScript and Google Maps.\n\nJavaScript \n\n```javascript\nimport React, { useState, useEffect, useRef } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport {\n APIProvider,\n ControlPosition,\n MapControl,\n AdvancedMarker,\n Map,\n useMap,\n useMapsLibrary,\n useAdvancedMarkerRef,\n} from \"@vis.gl/react-google-maps\";\nconst API_KEY = globalThis.GOOGLE_MAPS_API_KEY ?? \"YOUR_API_KEY\";\n\nconst App = () =\u003e {\n const [selectedPlace, setSelectedPlace] = useState(null);\n const [markerRef, marker] = useAdvancedMarkerRef();\n return (\n \u003cAPIProvider\n apiKey={API_KEY}\n solutionChannel=\"GMP_devsite_samples_v3_rgmautocomplete\"\n \u003e\n \u003cMap\n mapId={\"bf51a910020fa25a\"}\n defaultZoom={3}\n defaultCenter={{ lat: 22.54992, lng: 0 }}\n gestureHandling={\"greedy\"}\n disableDefaultUI={true}\n \u003e\n \u003cAdvancedMarker ref={markerRef} position={null} /\u003e\n \u003c/Map\u003e\n \u003cMapControl position={ControlPosition.TOP}\u003e\n \u003cdiv className=\"autocomplete-control\"\u003e\n \u003cPlaceAutocomplete onPlaceSelect={setSelectedPlace} /\u003e\n \u003c/div\u003e\n \u003c/MapControl\u003e\n \u003cMapHandler place={selectedPlace} marker={marker} /\u003e\n \u003c/APIProvider\u003e\n );\n};\n\nconst MapHandler = ({ place, marker }) =\u003e {\n const map = useMap();\n\n useEffect(() =\u003e {\n if (!map || !place || !marker) return;\n\n if (place.geometry?.viewport) {\n map.fitBounds(place.geometry?.viewport);\n }\n\n marker.position = place.geometry?.location;\n }, [map, place, marker]);\n return null;\n};\n\nconst PlaceAutocomplete = ({ onPlaceSelect }) =\u003e {\n const [placeAutocomplete, setPlaceAutocomplete] = useState(null);\n const inputRef = useRef(null);\n const places = useMapsLibrary(\"places\");\n\n useEffect(() =\u003e {\n if (!places || !inputRef.current) return;\n\n const options = {\n fields: [\"geometry\", \"name\", \"formatted_address\"],\n };\n\n setPlaceAutocomplete(new places.Autocomplete(inputRef.current, options));\n }, [places]);\n useEffect(() =\u003e {\n if (!placeAutocomplete) return;\n\n placeAutocomplete.addListener(\"place_changed\", () =\u003e {\n onPlaceSelect(placeAutocomplete.getPlace());\n });\n }, [onPlaceSelect, placeAutocomplete]);\n return (\n \u003cdiv className=\"autocomplete-container\"\u003e\n \u003cinput ref={inputRef} /\u003e\n \u003c/div\u003e\n );\n};\n\nconst root = createRoot(document.getElementById(\"app\"));\n\nroot.render(\u003cApp /\u003e);\nexport default App;https://github.com/googlemaps/js-samples/blob/2683f7366fb27829401945d2a7e27d77ed2df8e5/dist/samples/rgm-autocomplete/docs/index.jsx#L17-L104\n```\n| **Note:** The JavaScript is compiled from the TypeScript snippet.\n\nCSS \n\n```css\nbody {\n margin: 0;\n font-family: sans-serif;\n}\n\n#app {\n width: 100vw;\n height: 100vh;\n}\n\n.autocomplete-container input,\n.autocomplete-control {\n box-sizing: border-box;\n}\n\n.autocomplete-control {\n margin: 24px;\n background: #fff;\n}\n\n.autocomplete-container {\n width: 300px;\n}\n\n.autocomplete-container input {\n width: 100%;\n height: 40px;\n padding: 0 12px;\n font-size: 18px;\n}\n\n.autocomplete-container .custom-list {\n width: 100%;\n list-style: none;\n padding: 0;\n margin: 0;\n}\n\n.autocomplete-container .custom-list-item {\n padding: 8px;\n}\n\n.autocomplete-container .custom-list-item:hover {\n background: lightgrey;\n cursor: pointer;\n}\nhttps://github.com/googlemaps/js-samples/blob/2683f7366fb27829401945d2a7e27d77ed2df8e5/dist/samples/rgm-autocomplete/docs/style.css#L7-L53\n```\n\nHTML \n\n```html\n\u003chtml\u003e\n \u003chead\u003e\n \u003ctitle\u003eReact Google Maps - Autocomplete\u003c/title\u003e\n\n \u003clink rel=\"stylesheet\" type=\"text/css\" href=\"./style.css\" /\u003e\n \u003c/head\u003e\n \u003cbody\u003e\n \u003cdiv id=\"app\"\u003e\u003c/div\u003e\n \u003cscript type=\"module\" src=\"./index\"\u003e\u003c/script\u003e\n \u003c/body\u003e\n\u003c/html\u003ehttps://github.com/googlemaps/js-samples/blob/2683f7366fb27829401945d2a7e27d77ed2df8e5/dist/samples/rgm-autocomplete/docs/index.html#L8-L18\n```\n\nTry Sample \n[Google Cloud Shell](https://ssh.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fgooglemaps%2Fjs-samples&cloudshell_git_branch=sample-rgm-autocomplete&cloudshell_tutorial=cloud_shell_instructions.md&cloudshell_workspace=.)\n\nClone Sample\n\n\nGit and Node.js are required to run this sample locally. Follow these [instructions](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) to install Node.js and NPM. The following commands clone, install dependencies and start the sample application. \n\n git clone -b sample-rgm-autocomplete https://github.com/googlemaps/js-samples.git\n cd js-samples\n npm i\n npm start\n\n\nOther samples can be tried by switching to any branch beginning with `sample-`\u003cvar translate=\"no\"\u003eSAMPLE_NAME\u003c/var\u003e. \n\n git checkout sample-\u003cvar translate=\"no\"\u003e\u003cspan class=\"devsite-syntax-nx\"\u003eSAMPLE_NAME\u003c/span\u003e\u003c/var\u003e\n npm i\n npm start"]]