Add drop down for city in address form (Part 1)

When we create a Magento store for a specific location, we were asked to create drop down for city for customer address. It would replace normal text field by a drop down for billing and shipping address in checkout page. And it also replace customer address form in admin as well. I found an article which showed us how to replace city text field by a drop down using jQuery. It works but very slow if we have lots of cities. Finally, I found a simple solution which duplicates how Magento did for region drop down.
In this part, I will show you how to replace city text field by a drop down in billing address in checkout page. It’s the same thing for shipping address and other address form in frontend.
Step 1
Create a new javasript file called cityupdater.js

CityUpdater = Class.create();
CityUpdater.prototype = {
    initialize: function(countryEl, regionEl, cityTextEl, citySelectEl, cities) {
        this.regionEl = $(regionEl);
        this.cityTextEl = $(cityTextEl);
        this.citySelectEl = $(citySelectEl);
        this.cities = cities;
        this.countryEl = $(countryEl);
        if (this.citySelectEl.options.length<=1) {

        Event.observe(this.regionEl, 'change', this.update.bind(this));
        Event.observe(this.countryEl, 'change', this.update.bind(this));
        Event.observe(this.citySelectEl, 'change', this.updateCity.bind(this));

    update: function() {
        if (this.cities[this.regionEl.value]) {
            var i, option, city, def;
            def = this.citySelectEl.getAttribute('defaultValue');
            if (this.cityTextEl) {
                if (!def) {
                    def = this.cityTextEl.value.toLowerCase();
                this.cityTextEl.value = '';

            this.citySelectEl.options.length = 1;
            for (cityId in this.cities[this.regionEl.value]) {
                city = this.cities[this.regionEl.value][cityId];

                option = document.createElement('OPTION');
                option.value =;
                option.text =;
                option.title =;

                if (this.citySelectEl.options.add) {
                } else {

                if (cityId==def || ( && ||
                        ( && city.code.toLowerCase()==def)
                ) {
                    this.citySelectEl.value =;

            if (this.cityTextEl) {
       = 'none';
   = '';
        else {
            this.citySelectEl.options.length = 1;
            if (this.cityTextEl) {
       = '';
   = 'none';

    updateCity: function() {        
        var sIndex = this.citySelectEl.selectedIndex;
        this.cityTextEl.value = this.citySelectEl.options[sIndex].value;

Step 2

We need to rewrite billing.phtml of Magento. So in layout file of your module, add the following line:

<checkout_onepage_index translate="label">customaddress/checkout/onepage/billing.phtml

As defined in , we also need to load cityupdater.js in checkout page.

Step 3

Now copy Magento billing.phtml file into your own folder (which you defined above). Find this line:

And add the following code above it:

At the bottom of this file, add a line of code for creating Cityupdater class.

Step 4
Ok, now you need to create php functions which return city in a JSON format. You just need to simple to get all cities in an array which is the same as the following format:

$cities = array();
$cities[$region_id][$district_id] = array(
					'code'	=> $_item['city_code'],
					'name'	=> $_item['city_name']

And you need to encode the result into json format.

$helper = Mage::helper('core');
$json = $helper->jsonEncode($cities);

The code is quite complicated but I hope you can have a further look and make it work for your purpose. Any question, please comment.
Happy coding!

21 thoughts on “Add drop down for city in address form (Part 1)”

21 Responses to Add drop down for city in address form (Part 1)

  • David
    David on April 16, 2014 at 4:57 am said:

    Thank you very much for your post. It saves my day.

  • sebastian
    sebastian on April 20, 2014 at 8:53 am said:

    Neo, great post. I´ve been looking for nested dropdown in magento for days. my main question is if its possible to adapt this code in order to display categories in chained dropdowns instead of tree categories as it is usual. thank you so much

  • Bogdan
    Bogdan on April 22, 2014 at 12:22 pm said:

    Thank you for this! We had another approach (still trying to figure it out), but yours is much fancy :) We wait for the 2nd part.

  • Neo

    @Sebastian: where do you want to apply this change?

  • […] I’ve learn many articles however any individual supply me a concrete solution. The closest thing I’ve discovered is this article however it is not full but. […]

  • Finch

    Where can I get the city data? Should I put it in a text file? Or a database? Or hardcoded in the phtml file?

  • Neo

    There are many ways for you to get city data. You can create a page for city management in backend and save them in database.

  • vishal
    vishal on July 28, 2014 at 3:26 pm said:


    I have a API which has a all shops and address from which user can get it's product. now i need to integrate that API in magento and shipping cost will be calculate based on selection of that address and the API address will be in drop down. so is there any way that we can achieve that.

    Settings include:
    - Timeout for API call (SOAP or cURL)
    - Format to be used in the dropdown
    - API login information
    - Shipping price


  • hong

    A có thể cho em xin module add dropdown City khi chọn khi chọn Stat/Proinvce được không, em cám ơn nhiều lắm, vì e làm mà k được. hiện e đang rất cần gấp. nếu a cho e xin thì rất cám ơn

  • Tallal
    Tallal on August 17, 2015 at 12:07 pm said:

    Hi Neo, i just wanted to let you know that you two of your code lines are missing in Step 3. Could you please look into this?

  • Neo

    @Tallah: Yes, I've fixed the issue. Thank you

  • Bun Hin
    Bun Hin on December 6, 2015 at 12:20 pm said:

    Hi Neo, would you please to put more detail about where to put the cityupdater.js in the magento local module folder structure (if we want to do it as a local module), and also where to put the php function which return city as json format.

    Is the part 2 of this tutorial already published?

    Very appreciate if you can give some more detail on this tutorial so may help beginers like me.

    Bun Hin

  • bunhin

    Hi Neo,
    Would you please give some more detail on this tutorial such as where to put the cityupdater.js file in magento local module structure (if we want to make it as a module), and also where to put the fhp function which return city in json format.
    is it the part 2 already been published?

    Thank you.
    Bun Hin

  • bunhin

    Hi Neo,

    Could you please put some more detail in the tutorial : "Add drop down for city in address form (Part 1)", such as where to put cityupdaetr.js file in local module structure if we want to make it as an extension module. And also where to put the php function which return city in json format.

    have part 2 of this tutorial been published?

    Very appreciate for you to put more details so will help much beginers like me.

    Thank you and Regards,
    Bun Hin

  • Neo

    Hi Bun Hin, I am working on this. Next week, I will create a package for the module and release it as free for all users. It will be 2nd part of the blog as well :)

  • James

    Hi Neo,
    Thanks for the package. Is it ready?


  • Neo

    @everyone: you can download the module here

  • bunhin

    Hi Neo,

    Thank you for the response and the package. It is quite big, and give more than expected, make distance to my purpose shorter i believe. Please allow me to to write my goal with this dropdown, may be it will give more idea to make your package more excellent.

    For big country with city and also with rural area like Indonesia, the shipping cost for almost all carriers is differentiated until district (or sub city where one city will have 10-30 district or more sometimes) therefore i need to add district field after city and for better data integration and consistency to be used in shipping cost query more reliably, the select method during the address input is best i believe.

    So my purpose actually:
    1. add district field and
    2. make the input method for city, district, and zip code to be : "select" when data is populated or back to "text filed" when data is not populated. e.g for other country
    3. change the input field sequence to be in the following order : street address --> country -->State/Region ---> City --->District ----> Zip Code (the option will follow previous selection)
    4. create table directory_region_city and directory_region_city_district and directory_region_city_district_zipcode (since one district usually have more than 1 zipcode) with the helper
    5.the input/edit page is extra and more usefull when have feature to import csv, if this no 5 is not available populate through phpmyadmin will be ok.

    This your ImproveAddress package will be more excellent with added district and zipcode dropdown as above. So can be wrapped in one package.

    Please advice how to get there with your package.

    Sorry if too long.

    Thank you and Regards,

  • Zuby

    hi , how good is it if we can define shipping rate for each city ?

  • Ogunyemi
    Ogunyemi on May 10, 2016 at 3:59 pm said:

    The module cannot work when using another checkout module

  • Eleazer M
    Eleazer M on August 30, 2016 at 5:04 pm said:

    Interesting. Has anyone make this work with their magento Store?