kennzeichen

German license plate parsing and validation

Type a license plate to see it parsed

Installation

npm install kennzeichen

React Headless Component

import { LicensePlateInput } from "kennzeichen/react"

function MyInput({ value, onChange }) {
  return (
    <LicensePlateInput value={value} onChange={onChange}>
      {({ inputProps, isOpen, options }) => (
        <div>
          <input {...inputProps} />
          {isOpen && options?.map((opt) => (
            <button key={opt.formatted} {...opt.getProps()}>
              {opt.formatted}
            </button>
          ))}
        </div>
      )}
    </LicensePlateInput>
  )
}

React Hook

import { useLicensePlate, formatParsedPlate } from "kennzeichen/react"

function LicensePlateInput({ value, onChange }) {
  const { inputValue, handleChange, isDropdownOpen, options, selectOption } =
    useLicensePlate({ value, onChange })

  return (
    <div>
      <input value={inputValue} onChange={handleChange} />
      {isDropdownOpen && options?.map((opt, i) => (
        <button key={i} onClick={() => selectOption(opt)}>
          {formatParsedPlate(opt)}
        </button>
      ))}
    </div>
  )
}

Vanilla HTML + JavaScript

Use via CDN - no build step required:

<input type="text" id="plate-input" placeholder="Enter license plate...">
<div id="result"></div>

<script type="module" src="app.js"></script>
// app.js
import { parseLicensePlate, formatParsedPlate } from 
  "https://cdn.jsdelivr.net/npm/kennzeichen/+esm"

const input = document.getElementById("plate-input")
const result = document.getElementById("result")

input.addEventListener("input", (e) => {
  const parsed = parseLicensePlate(e.target.value)
  
  if (parsed.type === "unambiguous") {
    result.textContent = formatParsedPlate(parsed.plate)
  } else if (parsed.type === "ambiguous") {
    result.textContent = "Did you mean: " + 
      parsed.options.map(formatParsedPlate).join(" or ")
  } else if (parsed.type === "invalid") {
    result.textContent = "Invalid plate"
  }
})

Core API

Parse

import { parseLicensePlate } from "kennzeichen"

const result = parseLicensePlate("M-AB 1234")

if (result.type === "unambiguous") {
  console.log(result.plate)
  // { part1: "M", part2: "AB", part3: "1234" }
}

if (result.type === "ambiguous") {
  // User needs to pick one (try "CEE1234" in the demo above)
  console.log(result.options)
}

if (result.type === "invalid") {
  // Not a valid German license plate
}

Validate

import { isValidLicensePlate } from "kennzeichen"

isValidLicensePlate("M-AB 1234")   // true
isValidLicensePlate("XX-AB 1234")  // false (invalid location)

Format

import { formatParsedPlate } from "kennzeichen"

formatParsedPlate({ part1: "M", part2: "AB", part3: "1234" })
// "M-AB 1234"