erag/laravel-location-kit
Laravel Location Kit provides complete location datasets (countries, states, cities, currencies, timezones, dial codes) with Laravel-friendly APIs: facades/helpers, Blade directives, caching, search, Inertia shared props, plus bundled Vue composables and React hooks.
Installation:
composer require erag/laravel-location-kit
php artisan erag:install-location-kit
For Vue/React support:
npm install ./vendor/erag/laravel-location-kit/vue
# or
npm install ./vendor/erag/laravel-location-kit/react
First Use Case: Fetch country options in a Laravel controller:
use LaravelLocationKit\Facades\LocationKit;
$countries = LocationKit::countryOptions();
Or render them directly in Blade:
@locationCountries
Inertia Setup:
Enable Inertia sharing in config/location-kit.php:
'inertia' => [
'enabled' => true,
'share' => [
'countries' => true,
],
],
Access data in your Vue/React page via page.props.locationKit.
Facade API (Laravel):
// Get all countries as options
$countries = LocationKit::countryOptions();
// Get states for a country
$states = LocationKit::stateOptions('india');
// Get cities for a state
$cities = LocationKit::cityOptions('gujarat');
// Search across all datasets
$results = LocationKit::search('new york', 5);
Helper Functions (Global):
$countries = location_countries();
$states = location_states('us');
Blade Directives (Templates):
@locationCountries
@locationStates('india')
@locationCities('gujarat')
Vue Composable:
<script setup>
import { useLocationKit } from '@erag/laravel-location-kit/vue';
const { countries, statesForCountry, citiesForState } = useLocationKit();
const states = statesForCountry('india');
</script>
React Hook:
import { useLocationKit } from '@erag/laravel-location-kit/react';
function App() {
const { countries, statesForCountry } = useLocationKit();
const states = statesForCountry('us');
return <select>{states.map(...)}</select>;
}
<script setup>
import { useLocationKit } from '@erag/laravel-location-kit/vue';
const { maskPhone, phoneMaxLength } = useLocationKit();
const maskedPhone = maskPhone('india', '9876543210'); // "+91 98765 43210"
const maxLength = phoneMaxLength('india'); // 10
</script>
Configure config/location-kit.php to share data globally:
'inertia' => [
'enabled' => true,
'share' => [
'countries' => true,
'states' => true,
'currencies' => true,
'dial_codes' => true,
],
],
Access in any Inertia page via page.props.locationKit.
Example: Country → State → City cascading dropdowns:
<script setup>
import { ref } from 'vue';
import { useLocationKit } from '@erag/laravel-location-kit/vue';
const { statesForCountry, citiesForState } = useLocationKit();
const selectedCountry = ref('india');
const selectedState = ref('gujarat');
const states = statesForCountry(selectedCountry.value);
const cities = citiesForState(selectedState.value);
</script>
<template>
<select v-model="selectedCountry">
<option v-for="country in countries" :value="country.key">
{{ country.name }}
</option>
</select>
<select v-model="selectedState">
<option v-for="state in states" :value="state.key">
{{ state.name }}
</option>
</select>
<select v-model="selectedCity">
<option v-for="city in cities" :value="city.key">
{{ city.name }}
</option>
</select>
</template>
Place custom JSON files in storage/app/location/ (e.g., countries.json, states.json):
// storage/app/location/countries.json
[
{
"name": "Bharat",
"key": "india",
"countryCodes": ["91"],
"isoCode2": "IN",
"isoCode3": "IND"
}
]
Clear cache after updates:
php artisan location-kit:clear-cache
City Data Disabled by Default:
Cities are excluded from Inertia sharing by default for performance. Enable in config/location-kit.php:
'cities' => true
Then clear cache:
php artisan location-kit:clear-cache
Case Sensitivity in Keys:
Ensure key fields in custom JSON match the default dataset exactly (e.g., 'india' not 'India').
Inertia Prop Naming:
The shared prop name is configurable ('prop' => 'locationKit'). Ensure consistency across your app.
Phone Masking Edge Cases:
The maskPhone function assumes standard formats. For non-standard dial codes (e.g., +1 800), override the default JSON or extend the package.
Cache Invalidation: After overriding data, always run:
php artisan location-kit:clear-cache
Otherwise, changes may not reflect.
Large Datasets: Avoid loading all cities at once in Inertia. Use lazy loading or pagination for frontend rendering.
Check Data Paths:
Verify custom JSON files are in storage/app/location/ and permissions are correct (chmod -R 755 storage/app/location).
Validate JSON:
Use jsonlint.com to ensure custom JSON is valid before placing it in storage/app/location/.
Log Facade Output: Debug facade methods with:
dd(LocationKit::countries());
Frontend Console: For Vue/React issues, check browser console for errors in composables/hooks.
Custom Data Sources: While the package supports JSON overrides, future versions will add class-based customization. Track #12 for updates.
Add Postal Codes:
Extend the package by adding a postal_codes.json file to storage/app/location/ and updating the facade to include postal code methods.
Real-Time Geocoding: Combine with a service like Google Maps API for address autocomplete:
// Pseudocode for hybrid approach
$suggestedCities = LocationKit::cities('california');
$realTimeResults = GeocodingApi::search($query);
Localization:
Extend the Country, State, and City models to include localized names (e.g., name_en, name_es).
Testing: Mock the facade in tests:
LocationKit::shouldReceive('countries')->andReturn([...]);
Cache Aggressively:
The package caches data by default. For development, disable caching in config/location-kit.php:
'cache' => false
Lazy-Load Cities: If using cities, fetch them on-demand in the frontend:
<script setup>
const { citiesForState } = useLocationKit();
const cities = ref([]);
async function loadCities(stateKey) {
cities.value = await citiesForState(stateKey);
}
</script>
TypeScript Support: The Vue/React packages include TypeScript definitions. For custom types, extend the interfaces:
declare module '@erag/laravel-location-kit/vue' {
interface LocationKitCountry {
customField?: string;
}
}
Memoization:
Memoize expensive operations (e.g., statesForCountry) in Vue:
const states = computed(() => memoize(statesForCountry(selectedCountry.value)));
Error Boundaries: Wrap composable usage in error boundaries for graceful degradation:
<ErrorBoundary>
<LocationComponent />
How can I help you explore Laravel packages today?