Skip to main content

Using predefined state lists in Drupal 8

Back-end Development

Every now and again I find myself needing a list to use as select options in custom code, and whenever this occurs I wonder if there is a better way than hard coding the list in code. Depending on what framework is being used you might have options. Here is how you can accomplish this in Drupal (8=<).

There are two ways that I've discovered for doing this. Both require a contributed module, but they are very popular ones so the likelihood of you already having one installed is high. 

Using the Webform Module

The Webform module has an options structure that can be used for storing any list of items, and comes with many (30+) pre-built. These options use the WebformOptionsInterface. You can view all options available by visiting the following path on your site.


To use one of these option sets you simply need to load the webform_options entity type storage, and then load the option set you want. It's the same way you go about loading a node, vocabulary, etc, so it's likely familiar territory.

/** @var \Drupal\webform\WebformOptionsStorageInterface $webform_options_storage */
$webform_options_storage = $this->entityTypeManager->getStorage('webform_options');
/** @var \Drupal\webform\WebformOptionsInterface $states */
$states = $webform_options_storage->load('state_codes');
$state_options = $states->getOptions();

The nice thing about this is that all option sets are configurable and can be exported with configuration, so deployment is a breeze. For example, the state_codes include U.S. territories like Guam and D.C. In my case I only wanted the 50 official states so I was able to remove the handful of extra options to accomplish this.

I should also note that there are a few state lists available in Webform. One is called state_names and provides key/values that are both the full name of the region. state_codes on the other hand, provides the state two character code as the key, and the full name as the value.

Using the Addressing package

The second option involves using the addressing package provided by Centarro (The Commerce Guys). This module comes in handy any time you need to collect addresses. The addressing package itself extends beyond the Drupal framework, and then the drupal/address module integrates with the framework. The data set this library provides is much more extensive than webform in that it has global information, and sources the Unicode Common Locale Data Repository.

Here is a snippet of how you would pull in this data.

/** @var \CommerceGuys\Addressing\Subdivision\SubdivisionRepository $subdivisionRepository */
$subdivisionRepository = new SubdivisionRepository();
$states = $subdivisionRepository->getAll(['US']);
$state_options = array_map(function ($state) {
  /** @var \CommerceGuys\Addressing\Subdivision\Subdivision $state */
  return $state->getName();
}, $states);

One difference in this approach is that the lists are not configurable via the Drupal UI as they are with Webform. So pairing down the list to to remove other territories is something that needs to happen in code. This may be a plus to some, but I suspect most developers in the Drupal world will see this as a negative. This can be done any number of ways including the use of array_filter.


So, don't hard-code details like this in your code, because there are a few options that will handle it for you. It's also nice to know that a list of states isn't listed too many times in your sites code base.