I'm having an issue with addresses on Craft Commerce 3 (specifically the State field).

When a new customer adds an address, the State field defaults to a text field (not the expected Select field).

If you save the address and then go back, the State field turns back into the Select field (and defaults to Alabama). This is an issue because the form isn't actually collecting a valid State the first time through.

You can see reproduce this issue at https://renewable-lubricants.net/products/checkout/addresses

This issue is happening both on my modified templates as well as the latest stock Sample Templates, with no modifications.

The problem seems to be with this block of twig code below in "addresses/form.twig". Any idea what would make "options" fail the first time through?

<label for="{{ modelName }}-state">State</label>
                    {% set options = (model and states[model.countryId] is defined ? states[model.countryId] : []) %}
                    <select id="{{ modelName }}-stateId" data-modelname="{{ modelName }}" class="js-address-stateId w-full {% if options|length == 0 %}hidden{% endif %}" name="{{ modelName }}[stateValue]">
                        {% for key, option in options %}
                            {% set optionValue = (model ? model.stateId : '') %}
                            <option value="{{ key }}" {% if key == optionValue %}selected{% endif %}>{{ option }}</option>
                        {% endfor %}
                    <input type="text" data-modelname="{{ modelName }}" id="{{ modelName }}-stateName" class="js-address-stateName {% if options|length > 0 %}hidden{% endif %} w-full" {% if options|length == 0 %}name="{{ modelName }}[stateValue]"{% endif %} value="{{ model ? model.stateName : '' }}">
                    {% if model and model.getErrors('stateValue') %}
                        <span class="flash">{{ model.getErrors('stateValue')|join }}</span>
                    {% endif %}

Sample form fields

1 Answer 1


This is caused by the model.countryId not being defined on first page load, which means the options defaults to an empty array. Once the address is saved, the selected country that is saved will provide the countryId and therefore your states dropdown is populated the second time around.

IIRC, the sample Commerce templates hide the text field and show the states dropdown field via JavaScript based on the selected value of the country dropdown.

If you know you're always going to default to United States as the initially selected country, you could ensure your state text field is hidden by default and set a default country ID:

{# Note: example country ID #}
{% set defaultCountryId = 51 %}
{% set options = (model and states[model.countryId] is defined ? states[model.countryId] : states[defaultCountryId]) %}

I think you could get the correct country ID for the USA from craft.commerce.countries.allEnabledCountriesAsList to use with your default var.

  • Thanks so much! That worked for me. By the way I found my country ID by clicking edit on the United States in the Countries & States part of the CP.
    – Chris H.
    Commented Aug 4, 2020 at 19:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.