# Autocomplete-widget i ren JavaScript

> Sæt et adressefelt med forslag ind på en hvilken som helst side med ét script-tag, og fyld vej, postnummer og by i separate felter.
>
> https://danadresse.dk/guides/vanilla-autocomplete-widget · verified 2026-11-02
Vi har to færdige scripts til et adressefelt. De kræver ingen build-værktøjer, ingen frameworks og ingen andre biblioteker. Denne guide viser, hvilket du skal vælge, hvordan du sætter det op, og hvordan du får den valgte adresse ud i separate formularfelter.

Begge scripts kalder `/autocomplete` direkte fra brugerens browser. Nøglen ligger derfor i sidens kildekode og skal være en domænelåst browsernøgle. Læs [Browsernøgler og tilladte domæner](/guides/browser-noegler-domaener), før du går i produktion.

På en webshop-checkout, hvor du ikke kan skrive JavaScript, bruger du i stedet scriptet `https://api.danadresse.dk/js/danadresse-auto.min.js` med `data-key`. Det finder selv adressefelterne og udfylder vej, postnummer og by. Se platformssiderne under [/integrationer](/integrationer).

## 1. Vælg script

| | `danadresse-autocomplete-1.0.0.js` | `danadresse-widget.js` |
|---|---|---|
| Adresse | `https://danadresse.dk/static/js/danadresse-autocomplete-1.0.0.js` | `https://danadresse.dk/static/js/danadresse-widget.js` |
| Versioneret | Ja, filen ændres ikke | Nej, opdateres på stedet |
| Tilgængelighed | ARIA 1.2 combobox, live region, Home/End | ARIA 1.2 combobox, live region |
| Drill-down (vej → husnummer → enhed) | Ja | Ja |
| `onSelect` får | Et fladt objekt med vej, husnummer, postnummer osv. | Det rå forslag fra `/autocomplete` |
| Separate felter | Du skriver dem selv i `onSelect` (trin 5) | Indbygget: `fields: { street, postnr, city }` |
| Fejlvisning | Viser en besked og lader feltet virke som tekstfelt | En besked pr. årsag (nøgle, domæne, for mange søgninger, netværk) |
| Sprog | da, en, uk | Dansk tekst; kan overskrives med `messages` |

Brug `danadresse-autocomplete-1.0.0.js` til nye sider. `danadresse-widget.js` findes stadig og holdes opdateret, fordi eksisterende sider bruger den. Brug ét af dem pr. side. `danadresse-widget.js` registrerer altid `window.DanadresseWidget` og tager kun `window.DanadresseAutocomplete`, når 1.0.0 ikke er på siden, så de to overskriver ikke længere hinanden.

## 2. Indsæt feltet og scriptet

Et felt med label, scriptet og ét kald til `attach`:

```html id=basic-embed run=no
<label for="adr">Adresse</label>
<input id="adr" name="adresse" autocomplete="off">

<script src="https://danadresse.dk/static/js/danadresse-autocomplete-1.0.0.js"></script>
<script>
  const API_KEY = "dawa_live_din_browsernøgle"; // domænelåst nøgle

  DanadresseAutocomplete.attach("#adr", {
    apiKey: API_KEY,
    lang: "da",
    onSelect: function (a) {
      console.log(a.tekst, a.id);
    },
  });
</script>
```

Du kan også nøjes med attributter. Scriptet finder selv alle `input`-felter med `data-danadresse-key`, når siden er indlæst:

```html id=declarative-embed run=no
<input id="adr" data-danadresse-key="dawa_live_din_browsernøgle" data-danadresse-lang="da">
<script src="https://danadresse.dk/static/js/danadresse-autocomplete-1.0.0.js"></script>
```

De attributter, scriptet læser, er `data-danadresse-key`, `data-danadresse-lang`, `data-danadresse-type` og `data-danadresse-base`. Vil du have en `onSelect`, skal du bruge `attach` eller lytte efter eventet `danadresse:select` (se trin 4).

## 3. Indstillinger

| Option | Standard | Betydning |
|---|---|---|
| `apiKey` | ingen | Din browsernøgle. Uden nøgle svarer API'et 401, og feltet viser fejlbeskeden |
| `lang` | `<html lang>`, ellers `da` | `da`, `en` eller `uk`. Styrer pladsholder, tom-besked, fejlbesked og skærmlæsertekst |
| `type` | `adresse` | `adresse` (med etage/dør), `adgangsadresse` (stopper ved husnummer) eller `vejnavn` |
| `limit` | `8` | Antal forslag (`per_side`). API'et tillader højst 100 |
| `minLength` | `2` | Antal tegn, før der søges |
| `debounce` | `150` | Ventetid i millisekunder efter sidste tastetryk |
| `baseUrl` | `https://api.danadresse.dk` | Skift kun, hvis du kører kaldene gennem din egen proxy |
| `credit` | `true` | `false` fjerner linjen "Adresser fra danadresse.dk" |
| `fuzzy` | `true` | `false` sender `fuzzy=false` og slår tolerance for stavefejl fra. Standard: stavefejl rettes |
| `onSelect(a)` | ingen | Kaldes, når brugeren har valgt en endelig adresse |
| `onError(err)` | ingen | Kaldes ved netværksfejl eller HTTP-fejl. `err.status` er statuskoden |

`attach` returnerer et objekt med `close()`, `search(q)` og `destroy()`. Kalder du `attach` to gange på samme felt, får du det samme objekt tilbage, så der ikke kommer dobbelte lister.

## 4. Læs den valgte adresse

Med `type: "adresse"` sker valget i op til tre trin. Vælger brugeren et vejnavn, sætter scriptet vejnavnet ind, placerer markøren efter det og søger igen. Det samme sker for en opgang med flere lejligheder. `onSelect` kaldes først, når der er valgt en adresse af den type, du bad om.

`onSelect` får et fladt objekt:

```json id=onselect-payload run=no
{
  "type": "adresse",
  "tekst": "Rådhuspladsen 1, 3300 Frederiksværk",
  "id": "762a9a1f-a5fb-4e47-b1b2-9fa94026bc80",
  "adgangsadresseid": "0a3f507f-0959-32b8-e044-0003ba298018",
  "vejnavn": "Rådhuspladsen",
  "adresseringsvejnavn": "Rådhuspladsen",
  "vejkode": "1214",
  "kommunekode": "0260",
  "husnr": "1",
  "husnummer": "1",
  "husbogstav": null,
  "etage": null,
  "dør": null,
  "supplerendebynavn": null,
  "postnr": "3300",
  "postnrnavn": "Frederiksværk",
  "lat": 55.97657023,
  "lon": 12.01612365,
  "raw": { "type": "adresse", "tekst": "…", "data": { "…": "…" } }
}
```

`husnr` er husnummeret som én streng (`12A`). `husnummer` og `husbogstav` er det samme delt op (`12` og `A`), hvilket mange ERP- og fragtsystemer kræver. `raw` er det oprindelige forslag fra `/autocomplete`, hvis du skal bruge et felt, der ikke er i det flade objekt.

Feltet `dør` har et ø i navnet. Læs det med `a["dør"]` i JavaScript.

## 5. Udfyld separate felter

Mange formularer har vej, postnummer og by i hver sit felt. Lad brugeren søge i ét felt og skriv resultatet ud i de andre. Gem altid `id`: så kan du slå adressen op igen senere uden at parse tekst.

```html id=separate-fields run=no
<form id="levering">
  <label for="soeg">Find adresse</label>
  <input id="soeg">

  <label for="vej">Vej og nummer</label>
  <input id="vej" name="vej">
  <label for="etage">Etage og dør</label>
  <input id="etage" name="etage">
  <label for="postnr">Postnummer</label>
  <input id="postnr" name="postnr" inputmode="numeric">
  <label for="by">By</label>
  <input id="by" name="by">

  <input type="hidden" id="adresse_id" name="adresse_id">
</form>

<script src="https://danadresse.dk/static/js/danadresse-autocomplete-1.0.0.js"></script>
<script>
  const API_KEY = "dawa_live_din_browsernøgle";
  const f = document.getElementById("levering");

  DanadresseAutocomplete.attach("#soeg", {
    apiKey: API_KEY,
    onSelect: function (a) {
      f.vej.value = a.vejnavn + " " + a.husnr;
      f.etage.value = [a.etage ? a.etage + "." : "", a["dør"] || ""].join(" ").trim();
      f.postnr.value = a.postnr;
      f.by.value = a.postnrnavn;
      f.adresse_id.value = a.id;
    },
  });

  // Brugeren retter i felterne bagefter: id'et passer ikke længere.
  ["vej", "etage", "postnr", "by"].forEach(function (navn) {
    f[navn].addEventListener("input", function () { f.adresse_id.value = ""; });
  });
</script>
```

Hvis du ikke vil skrive en `onSelect`, kan du lytte efter eventet. Det bobler op gennem DOM'en med samme objekt i `detail`:

```js id=select-event run=syntax
document.addEventListener("danadresse:select", (e) => {
  const a = e.detail;
  console.log("Valgt:", a.tekst, a.postnr, a.postnrnavn);
});
```

## 6. Når API'et ikke svarer

Ved netværksfejl, 401, 403, 429 eller 5xx viser scriptet beskeden "Adresseopslag er utilgængeligt — skriv adressen manuelt", og feltet virker videre som et almindeligt tekstfelt. Din formular skal derfor kunne tage imod en adresse uden `id`. Vask den på serveren med `/datavask/adresser`, hvis du skal bruge koder.

Brug `onError` til at logge årsagen. `err.status` er `undefined` ved netværksfejl:

```js id=on-error run=syntax
const API_KEY = "dawa_live_din_browsernøgle";

DanadresseAutocomplete.attach("#adr", {
  apiKey: API_KEY,
  onError(err) {
    if (err.status === 403) console.warn("Tjek nøglens tilladte domæner");
    else if (err.status === 429) console.warn("For mange kald lige nu");
    else console.warn("Adresseopslag fejlede", err);
  },
});
```

Fejlsvar har CORS-headere, så browseren ser den rigtige statuskode og ikke bare en netværksfejl. En browsernøgle har en grænse pr. besøgende på 120 søgninger i minuttet. Over den svarer API'et 429 `rate_limit_per_visitor` med `Retry-After`, og feltet viser fejlbeskeden, indtil brugeren skriver igen.

`danadresse-widget.js` viser en dansk besked pr. årsag: manglende eller ugyldig nøgle (401), domænet er ikke tilladt (403), for mange søgninger (429) og netværksfejl. Dens `onError` får `{ kind }` med `unauthorized`, `forbidden`, `rate`, `network` eller `error`.

## 7. Se kaldet, som scriptet laver

Scriptet sender kun den indtastede tekst, markørens position, type, antal og `fuzzy`. Nøglen ligger i headeren `X-Api-Key`, og der sendes ingen cookies (`credentials: "omit"`). Du kan gentage kaldet fra terminalen:

```bash id=widget-request run=live expect="forslagstekst"
curl -s "https://api.danadresse.dk/autocomplete?q=Strandvejen%20100%2C%202900&type=adresse&per_side=8&fuzzy=" \
  -H "X-Api-Key: $DANADRESSE_API_KEY"
```

Svarer kaldet her, men ikke i browseren, er det næsten altid nøglens domæneliste. Se [Browsernøgler og tilladte domæner](/guides/browser-noegler-domaener).

## 8. Udseende, SRI og selv-hosting

Listen følger `prefers-color-scheme`. Farverne er CSS-variabler, som du kan overskrive:

```css id=theme-vars run=no
.dda2 {
  --dda2-bg: #ffffff;
  --dda2-fg: #1a1a1a;
  --dda2-active: #fff4d6;
  --dda2-link: #8a4b00;
}
```

Filen `danadresse-autocomplete-1.0.0.js` ændres aldrig, så du kan bruge Subresource Integrity. Beregn hashen for præcis den fil, du indlejrer, og sæt den i `integrity` sammen med `crossorigin="anonymous"`:

```bash id=sri-hash run=no
curl -s https://danadresse.dk/static/js/danadresse-autocomplete-1.0.0.js \
  | openssl dgst -sha384 -binary | openssl base64 -A
```

Du må også kopiere filen ind i din egen statiske mappe. Den er MIT-licenseret. Behold versionsnummeret i filnavnet, så du kan se, hvilken version du kører. Brug ikke SRI på `danadresse-widget.js` eller på aliaset `danadresse-autocomplete.js`: de er ikke versionerede, og hashen holder op med at passe, når filen opdateres.

## Næste skridt

- [Browsernøgler og tilladte domæner](/guides/browser-noegler-domaener) — lås nøglen til dit domæne.
- [Tilgængelig adresse-combobox](/guides/tilgaengelig-combobox) — sådan virker tastatur og skærmlæser i scriptet.
- [Adressefelt i React](/guides/react-autocomplete) — hvis du hellere vil bygge feltet selv.
- Live demo og flere eksempler: [/widget](/widget).
