Restaurant & Store Finder
This example demonstrates how to create a specialised location finder that searches for
specific business types. By using the includedPrimaryTypes parameter, you can build targeted search experiences for restaurants, cafés, shops, and other
establishments.
Live Demo
Select a business type below, then search for locations near you. The autocomplete will only show results matching your selected category.
powered by
How It Works
This example demonstrates how to build a specialised location finder by filtering results to specific business types.
- Place Type Filtering: Use the
includedPrimaryTypesparameter inrequestParamsto limit results to specific business categories like restaurants, cafés, or pharmacies. - Dynamic Type Switching: Update the search filter on-the-fly using
setRequestParams()when users select different business types, providing a seamless filtering experience. - Rich Place Information: The response includes valuable business data such as ratings, review counts, contact information, price levels, and business status that you can display to users.
- Enhanced User Experience: By focusing searches on specific business types, you eliminate irrelevant results and help users find exactly what they're looking for more quickly.
- Practical Applications: This pattern is perfect for restaurant finders, store locators, service directories, and any application where users need to find specific types of businesses or locations.
<script>
import { PlacesAutocomplete } from 'places-autocomplete-js';
document.addEventListener('DOMContentLoaded', () => {
let selectedType = 'restaurant';
let autocomplete;
// Place type buttons
const placeTypes = [
{ value: 'restaurant', label: 'Restaurants' },
{ value: 'cafe', label: 'Cafés' },
{ value: 'bar', label: 'Bars' },
{ value: 'bakery', label: 'Bakeries' },
{ value: 'supermarket', label: 'Supermarkets' },
{ value: 'pharmacy', label: 'Pharmacies' },
{ value: 'gas_station', label: 'Petrol Stations' },
{ value: 'bank', label: 'Banks' }
];
// Initialise Places Autocomplete
autocomplete = new PlacesAutocomplete({
containerId: 'restaurant-autocomplete-container',
googleMapsApiKey: 'YOUR_GOOGLE_MAPS_API_KEY',
onResponse: (placeDetails) => {
console.log('Place Selected:', placeDetails);
displayPlaceInfo(placeDetails);
},
onError: (error) => {
console.error('Autocomplete Error:', error.message || error);
},
requestParams: {
includedPrimaryTypes: [selectedType] // Filter by specific business type
},
fetchFields: [
'displayName',
'formattedAddress',
'rating',
'userRatingCount',
'internationalPhoneNumber',
'types',
'priceLevel',
'businessStatus',
'websiteURI',
'regularOpeningHours',
'editorialSummary'
],
options: {
placeholder: 'Search for restaurants, cafés, stores...',
clear_input: false,
show_place_type: true
}
});
// Create place type filter buttons
const typeContainer = document.getElementById('type-filter-container');
placeTypes.forEach(type => {
const button = document.createElement('button');
button.textContent = type.label;
button.classList.add('type-button');
if (type.value === selectedType) {
button.classList.add('active');
}
button.addEventListener('click', () => {
selectedType = type.value;
// Update active button styling
document.querySelectorAll('.type-button').forEach(btn => {
btn.classList.remove('active');
});
button.classList.add('active');
// Update autocomplete to search for new type
autocomplete.setRequestParams({
includedPrimaryTypes: [selectedType]
});
// Clear the input and results
autocomplete.clear();
document.getElementById('place-info').innerHTML = '';
});
typeContainer.appendChild(button);
});
function displayPlaceInfo(placeDetails) {
const infoContainer = document.getElementById('place-info');
// Format price level
const formatPriceLevel = (level) => {
const priceLevels = {
'INEXPENSIVE': { text: 'Budget-friendly', symbol: '£' },
'MODERATE': { text: 'Moderate pricing', symbol: '££' },
'EXPENSIVE': { text: 'Upmarket', symbol: '£££' },
'VERY_EXPENSIVE': { text: 'Fine dining', symbol: '££££' }
};
return priceLevels[level] || { text: level, symbol: '' };
};
// Build HTML for place information
let html = `
<div class="place-card">
<div class="place-header">
<h3>${placeDetails.displayName}</h3>
${placeDetails.businessStatus ?
`<span class="status ${placeDetails.businessStatus === 'OPERATIONAL' ? 'open' : 'closed'}">
${placeDetails.businessStatus === 'OPERATIONAL' ? 'Open' : 'Closed'}
</span>` : ''}
</div>
${placeDetails.editorialSummary ?
`<p class="editorial-summary">${placeDetails.editorialSummary}</p>` : ''}
${placeDetails.types ?
`<div class="types">
${placeDetails.types
.filter(t => !['point_of_interest', 'establishment', 'food'].includes(t))
.slice(0, 5)
.map(type => `<span class="type-badge">${type.replace(/_/g, ' ')}</span>`)
.join('')}
</div>` : ''}
<div class="rating-price">
${placeDetails.rating ?
`<div class="rating">
★ ${placeDetails.rating.toFixed(1)}
${placeDetails.userRatingCount ?
`<span>(${placeDetails.userRatingCount.toLocaleString()} reviews)</span>` : ''}
</div>` : ''}
${placeDetails.priceLevel ?
`<div class="price">
${formatPriceLevel(placeDetails.priceLevel).text}
<span>(${formatPriceLevel(placeDetails.priceLevel).symbol})</span>
</div>` : ''}
</div>
<div class="contact-details">
<h4>Contact Details</h4>
${placeDetails.formattedAddress ?
`<div class="detail">
<span class="icon">📍</span>
<span>${placeDetails.formattedAddress}</span>
</div>` : ''}
${placeDetails.internationalPhoneNumber ?
`<div class="detail">
<span class="icon">📞</span>
<a href="tel:${placeDetails.internationalPhoneNumber}">
${placeDetails.internationalPhoneNumber}
</a>
</div>` : ''}
${placeDetails.websiteURI ?
`<div class="detail">
<span class="icon">🌐</span>
<a href="${placeDetails.websiteURI}" target="_blank" rel="noopener noreferrer">
Visit website
</a>
</div>` : ''}
${placeDetails.id ?
`<div class="detail">
<span class="icon">🧭</span>
<a href="https://www.google.com/maps/search/?api=1&query=Google&query_place_id=${placeDetails.id}"
target="_blank" rel="noopener noreferrer">
Get directions
</a>
</div>` : ''}
</div>
${placeDetails.regularOpeningHours?.weekdayDescriptions ?
`<div class="opening-hours">
<h4>Opening Hours</h4>
${placeDetails.regularOpeningHours.weekdayDescriptions
.map(hours => `<div class="hours">🕐 ${hours}</div>`)
.join('')}
</div>` : ''}
</div>
`;
infoContainer.innerHTML = html;
}
});
</script>
<!-- Place Type Filter Buttons -->
<div id="type-filter-container" class="type-filters">
<!-- Buttons will be dynamically created here -->
</div>
<!-- Autocomplete Search Input -->
<div id="restaurant-autocomplete-container"></div>
<!-- Place Information Display -->
<div id="place-info"></div>
<style>
.type-filters {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1rem;
}
.type-button {
padding: 0.5rem 1rem;
border: 1px solid #ccc;
border-radius: 0.5rem;
background: #f9fafb;
cursor: pointer;
transition: all 0.2s;
}
.type-button.active {
background: #4f46e5;
color: white;
border-color: #4f46e5;
}
.place-card {
margin-top: 1.5rem;
padding: 1.5rem;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
background: white;
}
.place-header {
display: flex;
justify-content: space-between;
align-items: start;
margin-bottom: 1rem;
}
.status {
padding: 0.25rem 0.75rem;
border-radius: 0.25rem;
font-size: 0.875rem;
}
.status.open {
background: #dcfce7;
color: #166534;
}
.status.closed {
background: #fee2e2;
color: #991b1b;
}
.editorial-summary {
font-style: italic;
color: #6b7280;
margin-bottom: 1rem;
}
.types {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1rem;
}
.type-badge {
padding: 0.25rem 0.75rem;
background: #eef2ff;
color: #4f46e5;
border-radius: 0.25rem;
font-size: 0.875rem;
}
.rating-price {
display: flex;
gap: 2rem;
padding: 1rem 0;
border-top: 1px solid #e5e7eb;
border-bottom: 1px solid #e5e7eb;
margin-bottom: 1rem;
}
.contact-details h4,
.opening-hours h4 {
font-size: 0.875rem;
font-weight: 600;
text-transform: uppercase;
color: #6b7280;
margin-bottom: 0.75rem;
}
.detail {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 0.75rem;
}
.detail a {
color: #4f46e5;
text-decoration: none;
}
.opening-hours {
margin-top: 1rem;
padding-top: 1rem;
border-top: 1px solid #e5e7eb;
}
.hours {
margin-bottom: 0.5rem;
font-size: 0.875rem;
}
</style>