trinityrank/google-map-with-autocomplete
Laravel package for embedding Google Maps with place autocomplete. Adds an address/location input that suggests places as you type and links the selection to map coordinates, simplifying location picking in forms.
Install and publish
composer require trinityrank/google-map-with-autocomplete
php artisan vendor:publish --provider="Trinityrank\GoogleMapWithAutocomplete\GoogleMapWithAutocompleteServiceProvider"
If the provider name doesn't resolve, run php artisan vendor:publish interactively and look for the vendor tag, or grep vendor/trinityrank/google-map-with-autocomplete/composer.json for the extra.laravel.providers entry. On Laravel 5.5+ the provider and any facade should be auto-discovered — no config/app.php edit needed.
Where to look first (in this order):
vendor/trinityrank/google-map-with-autocomplete/src/ — the service provider tells you what's registered (Blade directive? component? view namespace? route?).config/google-map-with-autocomplete.php (or whatever the publish tag drops) — this is where the API key and map defaults live.resources/views/ inside the package — the Blade file is the feature. Read it before anything else; it shows the exact element IDs/classes the JS binds to.Configure the key
GOOGLE_MAPS_API_KEY=AIza...
Then php artisan config:clear. A missing key usually surfaces as a grey map or a console ApiNotActivatedMapError, not an exception.
First use case: an address picker on a checkout or profile form. The user types an address, picks a suggestion, and the component backfills the formatted address plus lat/lng into hidden inputs you validate and persist. Start with one form, one input, two hidden fields — don't wire it into every form on day one.
Basic form wiring. The component renders an input and the JS that attaches google.maps.places.Autocomplete. The pattern you want is: visible text input for the address, hidden inputs for coordinates, all inside your normal POST form.
<form method="POST" action="{{ route('addresses.store') }}">
@csrf
<x-google-map-autocomplete
name="address"
:lat="old('lat', $address->lat ?? null)"
:lng="old('lng', $address->lng ?? null)"
/>
<button type="submit">Save</button>
</form>
Confirm the actual prop/tag names against the package's Blade view — it's a thin wrapper, so reading 30 lines of markup is faster than guessing.
Validate on the server, always. The browser fills lat/lng only when the user selects a suggestion. Treat them as untrusted input:
$data = $request->validate([
'address' => ['required', 'string', 'max:255'],
'lat' => ['required', 'numeric', 'between:-90,90'],
'lng' => ['required', 'numeric', 'between:-180,180'],
]);
Store as decimal(10,7) and cast to float (or a small Coordinates value object) on the model — never as string, or distance math later gets ugly.
Reuse across forms. Wrap the component in your own Blade partial (resources/views/partials/address-picker.blade.php) that forwards name, lat, lng, and any country restriction. That gives you one place to change when you swap the package out — which, given its age, is a realistic future.
Livewire / SPA integration. Google Maps binds to the DOM node on init. Livewire's morphdom will destroy and recreate that node, leaving a dead map. Re-run the initializer after each update:
document.addEventListener('livewire:load', () => {
Livewire.hook('message.processed', () => window.initGoogleMapAutocomplete?.());
});
Same applies to Turbo/Turbolinks (turbo:load) and Inertia navigation.
Reading the selection yourself. If the package exposes a callback or you need more than address/lat/lng (place_id, city, postcode), attach your own listener after init:
const input = document.querySelector('#address');
const ac = new google.maps.places.Autocomplete(input, { types: ['address'] });
ac.addListener('place_changed', () => {
const p = ac.getPlace();
document.querySelector('#place_id').value = p.place_id ?? '';
});
This is also your escape hatch if the package's backfill logic doesn't cover a field you need.
Key hygiene. Use a browser-restricted key (HTTP referrer restricted, Maps JavaScript API + Places API enabled) for rendering, and a separate server-side key if you also do Geocoding/Distance Matrix in PHP. Never let the two share a key.
composer.json, and check it installs cleanly on your PHP/Laravel combination before designing around it. Expect no PHP 8.2+ deprecation fixes.place_changed never fired. Mitigate with a hint under the field, a client-side check, and hard server-side validation.You have included the Google Maps JavaScript API multiple times. Search your layout for maps.googleapis.com before blaming the package.config:cache bites. Change .env, forget php artisan config:clear, get the old key. Standard Laravel trap, but it looks like a package bug.google is not defined means the script tag was blocked (adblocker, CSP) or loaded after the package's inline init. Check the Network tab and your Content-Security-Policy for script-src/connect-src allowances for maps.googleapis.com and maps.gstatic.com.componentRestrictions: { country: 'gb' } if you only ship to one market — it dramatically improves suggestion relevance and reduces wrong-country selections.php artisan vendor:publish --tag=views (check the actual tag in the provider) lets you override the Blade file in resources/views/vendor/.... That's your cheapest customization path — change the input classes, add place_id, adjust hidden field names — without forking the package.places XHR on keystroke → window.google?.maps?.places truthiness → inspect the rendered input's id/class matches what the package's JS queries. Nine times out of ten the selector doesn't match because your layout changed the markup.Autocomplete, place_changed handler) is a realistic medium-term move if you need ongoing support or a Livewire/Alpine-friendly version.How can I help you explore Laravel packages today?