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-09-04 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-09-04 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,["# React Google Maps Library - Place Autocomplete\n\nThis 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\n### TypeScript\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\n### JavaScript\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\n### CSS\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\n### HTML\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\n### Try Sample\n\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\n### Clone 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"]]