Address autocomplete in Shopware 6

Load the one-tag address script from a Shopware 6 theme so every address form gets autocomplete, with postcode and city filled in the right form.

3 min Level: Intermediate ✓ Code tested

Shopware 6 uses the same address form for registration, in checkout and under "My addresses". The fields are named <prefix>[street], <prefix>[zipcode] and <prefix>[city], where the prefix is e.g. billingAddress, shippingAddress or address. Our one-tag script danadresse-auto knows these names and fills postcode and city with the same prefix, so shipping and billing addresses do not get mixed up.

1. Create a browser key

Create a live key under Keys and lock it to the shop's domains under Allowed domains, including your staging domain. If you have several sales channels with their own domains, all of them must be on the list. See Browser keys and allowed domains.

2. Load the script in the storefront

Extend base.html.twig in your theme, e.g. src/Resources/views/storefront/base.html.twig, and insert your browser key:

twig#auto-twig
{% sw_extends '@Storefront/storefront/base.html.twig' %}

{% block base_body_script %}
    {{ parent() }}
    <script src="https://api.danadresse.dk/js/danadresse-auto.min.js"
            data-key="YOUR_BROWSER_KEY" defer></script>
{% endblock %}

Clear the cache with bin/console cache:clear. An extension that adds header or footer scripts works too.

The script recognises billingAddress[street], shippingAddress[street] and address[street] with their [zipcode] and [city]. The names were checked against Shopware's own storefront templates. It also picks up forms that appear later, such as the address editor that checkout loads into a modal. When the customer picks a suggestion, street and number (with floor and door), postcode and city are filled. A typed address is checked when the customer leaves the field, with a "Did you mean …?" suggestion.

3. Test

Test three places: registration as a new customer, the address selection in checkout, and Account → Addresses. Type an address, pick a suggestion, and check that postcode and city land in the same form. API refused the request (403): … locked to … in the console means the domain is missing from the key. If your server sends a Content-Security-Policy header, https://api.danadresse.dk must be in both script-src and connect-src.

If your theme uses other field names, or you have a checkout plugin, add data-debug to the tag and read in the console which fields were found. Point the script at the fields with data-fields, e.g. data-fields='[{"street":"#my-street","zip":"#my-zip","city":"#my-city"}]'.

Or: your own init script

If you want full control over what is filled, attach the address widget yourself. Put the file in your theme or plugin bundle as src/Resources/public/danadresse-init.js:

JavaScript#init-js
const API_KEY = "YOUR_BROWSER_KEY";

function setField(el, value, events) {
  if (!el || value == null) return;
  const setter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el), "value").set;
  setter.call(el, value);
  for (const type of events || ["input", "change"]) {
    el.dispatchEvent(new Event(type, { bubbles: true }));
  }
}

function streetLine(a) {
  let line = a.vejnavn + " " + a.husnr;
  if (a.etage) line += ", " + a.etage + ".";
  if (a["dør"]) line += " " + a["dør"];
  return line;
}

// billingAddress[street] → billingAddress[zipcode] / billingAddress[city]
function sibling(input, field) {
  const name = input.name.replace("[street]", "[" + field + "]");
  return (input.form || document).querySelector('[name="' + name + '"]');
}

function bindAll() {
  document.querySelectorAll('input[name$="[street]"]').forEach((input) => {
    DanadresseAutocomplete.attach(input, {
      apiKey: API_KEY,
      onSelect(a) {
        setField(input, streetLine(a), ["change"]);
        setField(sibling(input, "zipcode"), a.postnr);
        setField(sibling(input, "city"), a.postnrnavn);
      },
    });
  });
}

function start() {
  bindAll();
  // The address editor in checkout is loaded with AJAX into a modal
  new MutationObserver(bindAll).observe(document.body, { childList: true, subtree: true });
}

if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", start);
else start();

Load it from base.html.twig in place of the script tag from step 2:

twig#base-twig
{% sw_extends '@Storefront/storefront/base.html.twig' %}

{% block base_body_script %}
    {{ parent() }}
    <script src="https://danadresse.dk/static/js/danadresse-autocomplete-1.0.0.js" defer></script>
    <script src="{{ asset('bundles/danadressetheme/danadresse-init.js') }}" defer></script>
{% endblock %}

bin/console assets:install copies src/Resources/public/ to public/bundles/<bundle name in lowercase>/. Adjust the path in asset() to match your bundle's name. Then clear the cache. With this route https://danadresse.dk must be in script-src too.

Optional: check the address on the server

A subscriber on CheckoutOrderPlacedEvent can send street, number and postcode to /datavask/adgangsadresser?betegnelse=… with a server key without a domain lock, and flag the order if the answer is category C. See Address cleansing in checkout for the categories.

Next steps

Related guides

Markdown source Spotted an error? Tell us API-reference (Swagger)

Try it with a free key

2,000 calls/month on the free plan. No credit card.

Create account →