# Adresse-autocomplete i Shopware 6

> Indlæs adresse-scriptet med ét tag fra et Shopware 6-theme, så alle adresseformularer får autocomplete, og postnr. og by havner i den rigtige formular.
>
> https://danadresse.dk/guides/shopware · verified 2026-11-02
Shopware 6 bruger den samme adresseformular ved registrering, i checkout og under "Mine adresser". Felterne hedder `<prefix>[street]`, `<prefix>[zipcode]` og `<prefix>[city]`, hvor præfikset fx er `billingAddress`, `shippingAddress` eller `address`. Vores script `danadresse-auto` med ét tag kender de navne og udfylder postnr. og by med samme præfiks, så leverings- og fakturaadressen ikke blandes sammen.

## 1. Opret en browsernøgle

Opret en *live*-nøgle under [Nøgler](/dashboard/keys) og lås den til butikkens domæner under **Tilladte domæner**, også dit staging-domæne. Har du flere saleschannels med hvert sit domæne, skal de alle på listen. Se [Browsernøgler og tilladte domæner](/guides/browser-noegler-domaener).

## 2. Indlæs scriptet i storefront'en

Udvid `base.html.twig` i dit theme, fx `src/Resources/views/storefront/base.html.twig`, og indsæt din browsernøgle:

```twig id=auto-twig run=no
{% 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="DIN_BROWSER_NØGLE" defer></script>
{% endblock %}
```

Ryd cachen med `bin/console cache:clear`. En udvidelse, der tilføjer header- eller footer-scripts, virker også.

Scriptet genkender `billingAddress[street]`, `shippingAddress[street]` og `address[street]` med tilhørende `[zipcode]` og `[city]`. Navnene er tjekket mod Shopwares egne storefront-skabeloner. Det fanger også formularer, der dukker op senere, fx adresse-editoren, som checkout'en henter ind i et modalvindue. Når kunden vælger et forslag, udfyldes vej og husnr. (med etage og dør), postnr. og by. En indtastet adresse tjekkes, når kunden forlader feltet, med et "Mente du …?"-forslag.

## 3. Test

Test tre steder: registrering som ny kunde, adressevalget i checkout'en, og **Konto → Adresser**. Skriv en adresse, vælg et forslag, og tjek at postnr. og by havner i samme formular. `API refused the request (403): … locked to …` i konsollen betyder, at domænet mangler på nøglen. Sender din server en `Content-Security-Policy`-header, skal `https://api.danadresse.dk` stå i både `script-src` og `connect-src`.

Bruger dit theme andre feltnavne, eller har du et checkout-plugin, så tilføj `data-debug` til tagget, og læs i konsollen, hvilke felter der blev fundet. Peg scriptet på felterne med `data-fields`, fx `data-fields='[{"street":"#min-vej","zip":"#mit-postnr","city":"#min-by"}]'`.

## Eller: dit eget init-script

Vil du have fuld kontrol over, hvad der udfyldes, så kobl adresse-widget'en på selv. Læg filen i dit theme- eller plugin-bundle som `src/Resources/public/danadresse-init.js`:

```js id=init-js run=syntax
const API_KEY = "DIN_BROWSER_NØGLE";

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();
  // Adresse-editoren i checkout'en hentes med AJAX i et modalvindue
  new MutationObserver(bindAll).observe(document.body, { childList: true, subtree: true });
}

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

Indlæs den fra `base.html.twig` i stedet for script-tagget fra trin 2:

```twig id=base-twig run=no
{% 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` kopierer `src/Resources/public/` til `public/bundles/<bundlenavn med små bogstaver>/`. Ret stien i `asset()`, så den passer til dit bundles navn. Ryd derefter cachen. Med denne vej skal `https://danadresse.dk` også stå i `script-src`.

## Valgfrit: tjek adressen på serveren

En subscriber på `CheckoutOrderPlacedEvent` kan sende vej, husnr. og postnr. til `/datavask/adgangsadresser?betegnelse=…` med en server-nøgle uden domænelås og markere ordren, hvis svaret er kategori C. Se [Datavask i checkout](/guides/datavask-i-checkout) for kategorierne.

## Næste skridt

- [Magento 2](/guides/magento), hvis du sammenligner med en anden PHP-platform
- [Browsernøgler og tilladte domæner](/guides/browser-noegler-domaener)
- [Integrationer](/integrationer)
