We are looking for maintainers!
In order to ensure active development going forward, we are looking for maintainers to join the project. Please contact the project owner if you are interested.
React Places Autocomplete
A React component to build a customized UI for Google Maps Places Autocomplete
Demo
Live demo: hibiken.github.io/react-places-autocomplete/
Features
- Enable you to easily build a customized autocomplete dropdown powered by Google Maps Places Library
- Utility functions to geocode and get latitude and longitude using Google Maps Geocoder API
- Full control over rendering to integrate well with other libraries (e.g. Redux-Form)
- Mobile friendly UX
- WAI-ARIA compliant
- Support Asynchronous Google script loading
Installation
To install the stable version
npm install --save react-places-autocomplete
React component is exported as a default export
import PlacesAutocomplete from 'react-places-autocomplete';
utility functions are named exports
import {
geocodeByAddress,
geocodeByPlaceId,
getLatLng,
} from 'react-places-autocomplete';
Getting Started
To use this component, you are going to need to load Google Maps JavaScript API
Load the library in your project
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>
Create your component
import React from 'react';
import PlacesAutocomplete, {
geocodeByAddress,
getLatLng,
} from 'react-places-autocomplete';
class LocationSearchInput extends React.Component {
constructor(props) {
super(props);
this.state = { address: '' };
}
handleChange = address => {
this.setState({ address });
};
handleSelect = address => {
geocodeByAddress(address)
.then(results => getLatLng(results[0]))
.then(latLng => console.log('Success', latLng))
.catch(error => console.error('Error', error));
};
render() {
return (
<PlacesAutocomplete
value={this.state.address}
onChange={this.handleChange}
onSelect={this.handleSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<input
{...getInputProps({
placeholder: 'Search Places ...',
className: 'location-search-input',
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => {
const className = suggestion.active
? 'suggestion-item--active'
: 'suggestion-item';
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: '#fafafa', cursor: 'pointer' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
);
}
}
Props
PlacesAutocomplete is a Controlled Component with a Render Prop. Therefore, you MUST pass at least value
and onChange
callback to the input element, and render function via children
.
Prop | Type | Required | Description |
---|
value | string | :white_check_mark: | value for the input element |
onChange | function | :white_check_mark: | onChange function for the input element |
children | function | :white_check_mark: | Render function to specify the rendering |
onSelect | function | | Event handler to handle user's select event |
onError | function | | Error handler function that gets called when Google Maps API responds with an error |
searchOptions | object | | Options to Google Maps API (i.e. bounds, radius) |
debounce | number | | Number of milliseconds to delay before making a call to Google Maps API |
highlightFirstSuggestion | boolean | | If set to true , first list item in the dropdown will be automatically highlighted |
shouldFetchSuggestions | boolean | | Component will hit Google Maps API only if this flag is set true |
googleCallbackName | string | | You can provide a callback name to initialize PlacesAutocomplete after google script is loaded |
value
Type: string
,
Required: true
onChange
Type: function
,
Required: true
Typically this event handler will update value
state.
<PlacesAutocomplete
value={this.state.value}
onChange={value => this.setState({ value })}
>
{}
</PlacesAutocomplete>
children
Type: function
Required: true
This is where you render whatever you want to based on the state of PlacesAutocomplete
.
The function will take an object with the following keys.
getInputProps
: functiongetSuggestionItemProps
: functionloading
: booleansuggestions
: array
Simple example
const renderFunc = ({ getInputProps, getSuggestionItemProps, suggestions }) => (
<div className="autocomplete-root">
<input {...getInputProps()} />
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => (
<div {...getSuggestionItemProps(suggestion)}>
<span>{suggestion.description}</span>
</div>
))}
</div>
</div>
);
<PlacesAutocomplete value={this.state.value} onChange={this.handleChange}>
{renderFunc}
</PlacesAutocomplete>;
getInputProps
This function will return the props that you can spread over the <input />
element.
You can optionally call the function with an object to pass other props to the input.
<input {...getInputProps({ className: 'my-input', autoFocus: true })} />
getSuggestionItemProps
This function will return the props that you can spread over each suggestion item in your
autocomplete dropdown. You MUST call it with suggestion
object as an argument, and optionally pass an object to pass other props to the element.
<div className="autocomplete-dropdown">
{suggestions.map(suggestion => (
<div {...getSuggestionItemProps(suggestion)}>
{suggestion.description}
</div>
))}
</div>
<div className="autocomplete-dropdown">
{suggestions.map(suggestion => {
const className = suggestion.active ? 'suggestion-item--active' : 'suggestion-item';
return (
<div {...getSuggestionItemProps(suggestion, { className })}>
{suggestion.description}
</div>
);
})}
</div>
loading
This is a boolean flag indicating whether or not the request is pending, or has completed.
suggestions
This is an array of suggestion objects each containing all the data from Google Maps API and other metadata.
An example of a suggestion object.
{
active: false,
description: "San Francisco, CA, USA",
formattedSuggestion: { mainText: "San Francisco", secondaryText: "CA, USA" },
id: "1b9ea3c094d3ac23c9a3afa8cd4d8a41f05de50a",
index: 0,
matchedSubstrings: [ {length: 8, offset: 0} ],
placeId: "ChIJIQBpAG2ahYAR_6128GcTUEo",
terms: [
{ offset: 0, value: "San Francisco" },
{ offset: 15, value: "CA" },
{ offset: 19, value: "USA" }
],
types: ["locality", "political", "geocode"]
}
onSelect
Type: function
Required: false
,
Default: null
You can pass a function that gets called instead of onChange
function when user
hits the Enter key or clicks on a suggestion item.
The function takes three positional arguments. First argument is address
, second is placeId
and third is the entire suggestion
object.
const handleSelect = (address: string, placeId: ?string, suggestion: ?object) => {
}
<PlacesAutocomplete
value={this.state.value}
onChange={this.handleChange}
onSelect={this.handleSelect}
>
{}
</PlacesAutocomplete>
onError
Type: function
Required: false
You can pass onError
prop to customize the behavior when google.maps.places.PlacesServiceStatus is not OK
(e.g., no predictions are found)
Function takes status
(string) and clearSuggestions
(function) as parameters
const onError = (status, clearSuggestions) => {
console.log('Google Maps API returned error with status: ', status)
clearSuggestions()
}
<PlacesAutocomplete
value={this.state.value}
onChange={this.handleChange}
onError={onError}
>
{}
</PlacesAutocomplete>
searchOptions
Type: Object
Required: false
Default: {}
You can fine-tune the settings passed to the AutocompleteService class with searchOptions
prop.
This prop accepts an object following the same format as google.maps.places.AutocompletionRequest
(except for input
, which comes from the value of the input field).
const searchOptions = {
location: new google.maps.LatLng(-34, 151),
radius: 2000,
types: ['address']
}
<PlacesAutocomplete
value={this.state.value}
onChange={this.handleChange}
searchOptions={searchOptions}
>
{}
</PlacesAutocomplete>
debounce
Type: number
Required: false
Default: 200
The number of milliseconds to delay before making a call to Google Maps API.
highlightFirstSuggestion
Type: boolean
Required: false
Default: false
If set to true
, first suggestion in the dropdown will be automatically set to be active.
shouldFetchSuggestions
Type: boolean
Required: false
Default: true
<PlacesAutocomplete
value={this.state.address}
onChange={this.handleChange}
shouldFetchSuggestions={this.state.address.length > 3}
>
{}
</PlacesAutocomplete>
googleCallbackName
Type: string
Required: false
Default: undefined
If provided, component will initialize after the browser has finished downloading google script.
IMPORTANT: To enable this async mode, you need to provide the same callback name to google script via callback=[YOUR CALLBACK NAME]
.
Example:
<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=myCallbackFunc"></script>
Then, provide googleCallbackName
prop to PlacesAutocomplete
.
<PlacesAutocomplete
value={this.state.value}
onChange={this.handleChange}
googleCallbackName="myCallbackFunc"
>
{}
</PlacesAutocomplete>
NOTE: If there are more than one PlacesAutocomplete
components rendered in the page,
set up a callback function that calls a callback function for each component.
Example:
<script>
window.myCallbackFunc = function() {
window.initOne && window.initOne();
window.initTwo && window.initTwo();
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=myCallbackFunc"></script>
<PlacesAutocomplete
value={this.state.value}
onChange={this.handleChange}
googleCallbackName="initOne"
>
{}
</PlacesAutocomplete>
<PlacesAutocomplete
value={this.state.value}
onChange={this.handleChange}
googleCallbackName="initTwo"
>
{/* custom render function */}
</PlacesAutocomplete>
Utility Functions
geocodeByAddress
API
geocodeByAddress(address);
address
Type: String
,
Required: true
String that gets passed to Google Maps Geocoder
import { geocodeByAddress } from 'react-places-autocomplete';
geocodeByAddress('Los Angeles, CA')
.then(results => console.log(results))
.catch(error => console.error(error));
geocodeByPlaceId
API
geocodeByPlaceId(placeId);
placeId
Type: String
,
Required: true
String that gets passed to Google Maps Geocoder
import { geocodeByPlaceId } from 'react-places-autocomplete';
geocodeByPlaceId('ChIJE9on3F3HwoAR9AhGJW_fL-I')
.then(results => console.log(results))
.catch(error => console.error(error));
getLatLng
API
getLatLng(result);
result
Type: Object
Required: true
One of the element from results
(returned from Google Maps Geocoder)
import { geocodeByAddress, getLatLng } from 'react-places-autocomplete';
geocodeByAddress('Tokyo, Japan')
.then(results => getLatLng(results[0]))
.then(({ lat, lng }) =>
console.log('Successfully got latitude and longitude', { lat, lng })
);
Discussion
Join us on Gitter if you are interested in contributing!
License
MIT