React Google Maps Library - Place Autocomplete

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.

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 
 ; 
  

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 
 ; 
  

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 
 
Create a Mobile Website
View Site in Mobile | Classic
Share by: