Skip to content

canida-software/kennzeichen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kennzeichen

German license plate parsing and validation. Framework-agnostic core with React adapter.

Live Demo

Installation

npm install kennzeichen

Features

  • Parse German license plates with ambiguity detection
  • 726 valid location codes (Unterscheidungszeichen)
  • Handles E (electric) and H (historic) suffixes
  • Framework-agnostic core
  • React hook + headless component

Usage

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

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
  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"

API Reference

Core

parseLicensePlate(input: string): ParseResult

Parses a license plate input string. Handles various formats: "M-AB 1234", "M AB 1234", "MAB1234".

formatParsedPlate(plate: Partial<ParsedPlate>): string

Formats a parsed plate into standard display format: "M-AB 1234".

isValidLicensePlate(input: string): boolean

Returns true if the input is a valid, unambiguous German license plate.

sanitizeLicensePlate(plate: string): string

Removes all spaces and hyphens from a license plate string.

LOCATION: string[]

Array of all 726 valid German location codes.

React

<LicensePlateInput> (Headless Component)

Render props component for license plate input.

Props:

  • value?: string - Controlled value
  • onChange?: (value: string) => void - Called when value changes
  • children: (props: RenderProps) => ReactNode - Render function

RenderProps:

  • inputProps - Props to spread on input element
  • isOpen: boolean - Whether dropdown should be visible
  • options: OptionItem[] | null - Disambiguation options with helper methods

useLicensePlate(options): UseLicensePlateReturn

React hook for managing license plate input state.

Options:

  • value?: string - Controlled value
  • onChange?: (value: string) => void - Called when value changes

Returns:

  • inputValue: string - Current input value
  • handleChange - Input onChange handler
  • isDropdownOpen: boolean - Whether dropdown should be visible
  • options: ParsedPlate[] | null - Disambiguation options
  • selectOption(option) - Select a disambiguation option

Types

type ParseResult =
  | { type: "unambiguous"; plate: ParsedPlate }
  | { type: "ambiguous"; options: ParsedPlate[] }
  | { type: "partial"; plate: Partial<ParsedPlate> }
  | { type: "invalid" }

type ParsedPlate = {
  part1: string  // Location code (e.g., 'M', 'HH', 'BGL')
  part2: string  // Letters (e.g., 'AB', 'X')
  part3: string  // Numbers + optional suffix (e.g., '1234', '99E', '42H')
}

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published