On the otherhand, if the dataset is large, the options for the second select might need to be queried from the backend. This then adds the challenge of creating an AJAX request in the browser, creating an API on the server side, and merging the returned data into the current document.
I decided to see just how simple this could be using Livewire by Caleb Porzio. Livewire provides client side components that are ‘hotwired’ to Laravel components, providing two-way data-binding and automatic DOM updates.
If you already have a project with suitable dataset, then you can skip this section.
I started with a new Laravel project (in the examples below, using Tailwind, but not relevant) and then added a dataset that could be used by the dropdowns.
After (not much!) searching, I came across a Laravel package of countries and cities which seemed it would be suitable. Other datasets are available, but this one migrated then seeded the database tables.
Unfortunately, the package has not been recently maintained and does not understand that the string helpers have been removed. For our purposes this is not a great issue, we can create new Eloquent models and just tell them to use the world_ tables;
~/Sites/livewire (master) $ php artisan make:model Country
~/Sites/livewire (master) $ php artisan make:model City
// Country model
protected $table = 'world_countries';
protected $table = 'world_cities';
composer require livewire/livewire
class Dropdowns extends Component
public function mount($country, $city)
public function render()
$this->cities = City::where('country_id', $this->country)->get();
Ok, some new stuff to get to grips with here. The public attributes are shared with the view ‘live’ whatever the public property contains, the view has access to. Initially, the cities is an empty array, as until we select a country we don’t know which cities to show.
Skip over the mount() method for a moment, we will cover that later.
The render() method is called whenever one of the elements in the view component changes, such as when the user changes the Country dropdown. Before invoking render, Livewire re-hydrates the public properties of the component. Thanks to the wire:model attribute on the select element, the select’s value is bound to the country property. We can then use this to set the cities array using an Eloquent query. When the render method ends by returning the view component, the view is updated with the cities populated in the second dropdown.
Extra: The Mount() method
Suppose these dropdowns are on an edit page, where the user’s previous selection must be presented. The previous values can be passed into the @livewire directive;
The additional two properties are passed into the mount() method where they can be used to initialise the country and city public properties of the Dropdown component. Since the data is bound two-way to the select element, when the page is rendered, the previous entries will be selected.