A React component to build a customized UI for Google Maps Places Autocomplete
Live demo: kenny-hibino.github.io/react-places-autocomplete/
- 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
- Pass through arbitrary props to the input element to integrate well with other libraries (e.g. Redux-Form)
- Mobile friendly UX
- WAI-ARIA compliant
To install the stable version
yarn add react-places-autocomplete
or
npm install react-places-autocomplete --save
React component is exported as a default export
import PlacesAutocomplete from 'react-places-autocomplete';
geocodeByAddress
and geocodeByPlaceId
utility functions are named exports
import {geocodeByAddress, geocodeByPlaceId} from 'react-places-autocomplete';
To use this component, you are going to need to load Google Maps JavaScript API
Load the library in your project
<script type="text/javascript" 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 SimpleForm extends React.Component {
constructor(props) {
super(props);
this.state = {
address: '123 Lombard Stree, San Francisco, CA',
formattedAddress: {
mainText: '123 Lombard Street',
secondaryText: 'San Fransisco, CA, USA',
},
};
this.onChange = (address, formattedAddress) =>
this.setState({address, formattedAddress});
}
handleFormSubmit = event => {
event.preventDefault();
geocodeByAddress(this.state.address)
.then(results => getLatLng(results[0]))
.then(latLng => console.log('Success', latLng))
.catch(error => console.error('Error', error));
};
render() {
const inputProps = {
value: this.state.address,
onChange: this.onChange,
};
return (
<form onSubmit={this.handleFormSubmit}>
<PlacesAutocomplete inputProps={inputProps} />
<button type="submit">Submit</button>
</form>
);
}
}
export default SimpleForm;
Prop | Type | Required | Description |
---|---|---|---|
inputProps |
object | ✅ | Arbitrary props to input element, value and onChange are required keys |
renderSuggestion |
function | Functional react component to render dropdown list item | |
renderFooter |
function | Functional react component to render footer at the bottom of the dropdown list | |
classNames |
object | Pass CSS classes to rendered elements | |
styles |
object | Pass CSS styles to rendered elements | |
onSelect |
function | Event handler to handle user's select event | |
onEnterKeyDown |
function | Event handler that gets called when user presses Enter key while input is focused | |
onError |
function | Error handler function that gets called when Google Maps API responds with an error | |
options |
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 |
function | Component will fetch suggestions from Google Maps API only when this function returns true |
Type: Object
,
Required: true
PlacesAutocomplete is a controlled component. Therefore, you MUST pass at least value
and onChange
callback to the input element.
You can pass arbitrary props to the input element thorough inputProps
object (NOTE: className
and style
props for the input element should be passed through classNames.input
and styles.input
respectively).
const inputProps = {
value, // `value` is required
onChange, // `onChange` is required
onBlur: () => {
console.log('blur!');
},
type: 'search',
placeholder: 'Search Places...',
autoFocus: true,
};
Type: Functional React Component
,
Required: false
The function takes props with suggestion
, formattedSuggestion
keys (see the example below).
We highly recommend that you create your own custom list item component and pass it as a prop.
/***********************************************
Example #1
List item example with `suggestion`
************************************************/
render() {
const renderSuggestion = ({ suggestion }) => (<div><i className="fa fa-map-marker"/>{suggestion}</div>)
return (
<PlacesAutocomplete
inputProps={inputProps}
renderSuggestion={renderSuggestion}
/>
)
}
/***************************************************
Example #2
List item example with `formattedSuggestion`
****************************************************/
render() {
const renderSuggestion = ({ formattedSuggestion }) => (
<div>
<strong>{ formattedSuggestion.mainText }</strong>{' '}
<small>{ formattedSuggestion.secondaryText }</small>
</div>
)
return (
<PlacesAutocomplete
inputProps={inputProps}
renderSuggestion={renderSuggestion}
/>
)
}
Type: Functional React Component
Required: false
You can provide a component that will get rendered at the bottom of dropdown. For example, you can provide a component to show "Powered by Google" logo.
const renderFooter = () => (
<div className="dropdown-footer">
<div>
<img src={require('./images/google-logo.png')} />
</div>
</div>
)
// In render function
<PlacesAutocomplete
inputProps={inputProps}
renderFooter={renderFooter}
/>
Type: Object
,
Required: false
You can give a custom css classes to elements.
Accepted keys are root
, input
, autocompleteContainer
, autocompleteItem
, autocompleteItemActive
.
If you pass classNames
props, none of the default inline styles nor inline styles from styles
prop will
be applied to the element, and you will have full control over styling via CSS.
// classNames example
render() {
const cssClasses = {
root: 'form-group',
input: 'form-control',
autocompleteContainer: 'my-autocomplete-container'
}
return (
<PlacesAutocomplete
inputProps={inputProps}
classNames={cssClasses}
/>
)
}
Now you can easily apply custom CSS styles using the classNames!
Type Object
,
Required: false
You can provide custom inline styles to elements.
Accepted keys are root
, input
, autocompleteContainer
, autocompleteItem
, autocompleteItemActive
.
const defaultStyles = {
root: {
position: 'relative',
paddingBottom: '0px',
},
input: {
display: 'inline-block',
width: '100%',
padding: '10px',
},
autocompleteContainer: {
position: 'absolute',
top: '100%',
backgroundColor: 'white',
border: '1px solid #555555',
width: '100%',
},
autocompleteItem: {
backgroundColor: '#ffffff',
padding: '10px',
color: '#555555',
cursor: 'pointer',
},
autocompleteItemActive: {
backgroundColor: '#fafafa',
},
};
Object passed via styles
prop will be merged in with the above defaults and applied to their respective elements.
NOTE: Passing classNames
will disable any inline styling for respective elements.
// custom style examples
render() {
const myStyles = {
root: { position: 'absolute' },
input: { width: '100%' },
autocompleteContainer: { backgroundColor: 'green' },
autocompleteItem: { color: 'black' },
autocompleteItemActive: { color: 'blue' }
}
return (
<PlacesAutocomplete
inputProps={inputProps}
styles={myStyles}
/>
)
}
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 an autocomplete item.
The function takes two positional arguments. First argument is address
, second is placeId
.
const handleSelect = (address, placeId) => {
this.setState({ address, placeId })
// You can do other things with address string or placeId. For example, geocode :)
}
// Pass this function via onSelect prop.
<PlacesAutocomplete
inputProps={inputProps}
onSelect={this.handleSelect}
/>
Type: Function
Required: false
Deafult: noop
You can pass a callback function that gets called when pressing down Enter key when no item in the dropdown is selected. The function takes one argument, the value in the input field.
const handleEnter = (address) => {
geocodeByAddress(address)
.then(results => {
console.log('results', results)
})
}
// Pass this function via onEnterKeyDown prop.
<PlacesAutocomplete
inputProps={inputProps}
onEnterKeyDown={this.handleEnter}
/>
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
// Log error status and clear dropdown when Google Maps API returns an error.
const onError = (status, clearSuggestions) => {
console.log('Google Maps API returned error with status: ', status)
clearSuggestions()
}
// In render function
<PlacesAutocomplete
inputProps={inputProps}
onError={onError}
/>
Type: Object
Required: false
Default: {}
You can fine-tune the settings passed to the AutocompleteService class with options
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).
// these options will bias the autocomplete predictions toward Sydney, Australia with a radius of 2000 meters,
// and limit the results to addresses only
const options = {
location: new google.maps.LatLng(-34, 151),
radius: 2000,
types: ['address']
}
// In render function
<PlacesAutocomplete
inputProps={inputProps}
options={options}
/>
Type: Number
Required: false
Default: 200
The number of milliseconds to delay before making a call to Google Maps API.
Type: Boolean
Required: false
Default: false
If set to true
, first suggestion in the dropdown will be automatically highlighted.
Type: Function
Required: false
Default: () => true
You can pass a function to tell when to fetch suggestions from Google Maps API.
It takes an input { value }
and should return a boolean.
// Only fetch suggestions when the input text is longer than 3 characters.
const shouldFetchSuggestions = ({ value }) => value.length > 3
// In render function
<PlacesAutocomplete
inputProps={inputProps}
shouldFetchSuggestions={shouldFetchSuggestions}
/>
/**
* Returns a promise
* @param {String} address
* @return {Promise}
*/
geocodeByAddress(address);
Type: String
,
Required: true
String that gets passed to Google Maps Geocoder
import {geocodeByAddress} from 'react-places-autocomplete';
// `results` is an entire payload from Google API.
geocodeByAddress('Los Angeles, CA')
.then(results => console.log(results))
.catch(error => console.error(error));
/**
* Returns a promise
* @param {String} placeId
* @return {Promise}
*/
geocodeByPlaceId(placeId);
Type: String
,
Required: true
String that gets passed to Google Maps Geocoder
import {geocodeByPlaceId} from 'react-places-autocomplete';
// `results` is an entire payload from Google API.
geocodeByPlaceId('ChIJE9on3F3HwoAR9AhGJW_fL-I')
.then(results => console.log(results))
.catch(error => console.error(error));
/**
* Returns a promise
* @param {Object} result
* @return {Promise}
*/
getLatLng(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}),
);
Join us on Gitter if you are interested in contributing!
MIT