๐ European license plate validator (Russia excluded). Multi-country, regex-based validation for EU/EEA license plates. Works in Node.js, TypeScript, and the browser (with a lightweight UI client).
@codecorn/euro-plate-validator npm downloads jsDelivr GitHub stars
CI Tests issues min minzip Types module cdn License
- โ Multi-country support (25+ EU/EEA)
- ๐ซ Russia excluded by design
- ๐ Normalizes input (spaces, hyphens, case)
- ๐ง Smart regex engine per-country (car/motorcycle aware)
- ๐งฉ Lightweight client SDK with UI, flags, dropdown, and
Inputmaskintegration โ๏ธ Accepts lowercase input, auto-coerced to UPPERCASE by mask tokenL- ๐ Built-in i18n: IT and EN
- ๐งฏ Safe dependency autoload via CDN with configurable overrides
npm install @codecorn/euro-plate-validator
Use versioned URLs to avoid stale CDN caches.
-
ESM (browser)
https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/browser/index.esm.js -
IIFE (global
window.EuroPlateValidator)https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/browser/index.iife.min.js
-
ESM
https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/client/index.mjs -
CJS (Node)
https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/client/europlate.client.cjs
https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/assets/css/styles.css- (compat alias)
.../assets/css/styles.css
import { validatePlate } from "@codecorn/euro-plate-validator"; // Italy (car) validatePlate("AB 123 CD", ["IT"], { vehicleType: "car" }); // โ { isValid: true, matches: [{country:"IT", name:"Italy"}], checked:["IT"] } // UK vs IE validatePlate("AB12 CDE", ["UK", "IE"]);
The browser client auto-generates a full UI (flag + input + dropdown + status) or attaches to an existing <input>. ecco la versione EN tradotta 1 : 1 . Ho lasciato il codice invariato , e ho applicato lo spazio prima / dopo la punteggiatura solo al testo in prosa .
import { validatePlate } from "@codecorn/euro-plate-validator"; // IT (car) validatePlate("AB 123 CD", ["IT"], { vehicleType: "car" }); // โ { isValid: true, matches:[{country:"IT", name:"Italy"}], checked:["IT"] } // UK vs IE validatePlate("AB12 CDE", ["UK", "IE"]);
The client either generates the markup ( flag + input + country dropdown + status ) or attaches to an existing input .
type EuroPlateOptions = { // DOM input?: HTMLInputElement; // external input wrapper?: string | HTMLElement | false; // if provided โ auto-build UI inputId?: string; // default: derived ( e.g., "epv-xxxx-plate" ) inputName?: string; // default: same preserveInputAttrs?: boolean; // NEW: if true, does NOT overwrite existing id/name autoFocusOnInit?: boolean; // NEW: default false ( no focus on init ) // โ๏ธ UI configuration ( new: EVERYTHING under "ui" ) ui?: { /** * Where to show the status : * - "block" โ uses <div class="status"> under the input ( back-compat , default ) * - "inline" โ overlays inside the input , does not change height * - "off" โ hides status text / icon */ statusMode?: "block" | "inline" | "off"; // default: "block" /** Icon type for inline status ( ignored in "block" and "off" ) */ statusIcon?: "none" | "icon" | "pill"; // default: "none" /** Whether to show status text */ showStatusText?: boolean; // default: blockโtrue , inlineโfalse /** Inline icon position */ iconPosition?: "right" | "left"; // default: "right" // Optional references to existing nodes ( when NOT using wrapper ) flagIcon?: HTMLElement; flagLabel?: HTMLElement; dropdown?: HTMLElement; button?: HTMLElement; status?: HTMLElement; }; // UX / i18n mode?: "AUTO" | string; // fixed country or AUTO ( default ) i18n?: "AUTO" | "IT" | "EN"; // default AUTO โ navigator it / en allowedCountries?: string[]; // whitelist ; default : all vehicleType?: "any" | "car" | "bike"; // default : any placeholders?: { auto?: string }; // placeholder for AUTO // Normalization / formatting normalize?: (code: string) => string; // default GBโUK formatters?: Record<string, (s: string) => string>; // per country code // Timings timings?: { debounce?: number; clear?: number }; // Dependencies / logging deps?: { inputmask?: any }; // manual inject ( e.g., window.Inputmask ) autoLoadDeps?: { inputmask?: boolean }; // default : true ( autoload UMD ) cdn?: { inputmask?: string }; // override Inputmask CDN URL logger?: Logger; debug?: boolean; };
| Key | Type | Values | Default | Notes |
|---|---|---|---|---|
ui.statusMode |
"block" | "inline" | "off" |
block / inline / off | "block" |
block uses <div class="status"> , inline overlays inside the input , off hides UI |
ui.statusIcon |
"none" | "icon" | "pill" |
none / icon / pill | "none" |
used only when statusMode is inline |
ui.showStatusText |
boolean |
true / false | blockโtrue , inlineโfalse |
short text in inline ; full text in block |
ui.iconPosition |
"right" | "left" |
right / left | "right" |
icon position for inline |
ui.status |
HTMLElement ( optional ) |
โ | auto created / derived | existing host for status when you do not use wrapper |
ui.button / dropdown / flagIcon / flagLabel |
HTMLElement ( optional ) |
โ | auto created if wrapper |
for re-using external DOM |
type EuroPlateInstance = { setCountry(code: "AUTO" | string): void; // alias of setMode setMode(m: "AUTO" | string): void; // set fixed country or AUTO setAllowed(codes: string[]): void; // dynamic whitelist setVehicleType(t: "any" | "car" | "bike"): void; setI18n(code: "AUTO" | "IT" | "EN"): void; setDebug(on: boolean): void; validate(): { ok: boolean; country?: string; value: string }; destroy(): void; getI18n(): "it" | "en"; };
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/assets/css/styles.css" /> <div id="plateBox"></div> <script type="module"> import * as EuroMod from "https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/browser/index.esm.js"; import { createEuroPlate } from "https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/client/index.mjs"; // Common options used across examples const common = { mode: "AUTO", i18n: "IT", allowedCountries: ["IT", "FR", "DE", "ES"], vehicleType: "any", autoFocusOnInit: false, ui: { statusMode: "inline", statusIcon: "icon", showStatusText: true, // | false iconPosition: "right", }, // Autoload deps (UMD) from CDN autoLoadDeps: { inputmask: true, jquery: true, toastr: true }, // Optional : route logs to Toastr if available useToastrLogger: true, debug: true, }; createEuroPlate(EuroMod, { wrapper: "#plateBox", // optional ...common, }); </script>
Notes :
- With
autoLoadDeps.jquery: trueandautoLoadDeps.toastr: truethe client will fetch UMD builds from CDN when missing .useToastrLogger: truesends SDK logs and validation notices to Toastr if it is present ( either auto-loaded or injected ) .- jQuery is not required by the core validator ; it is only pulled if your page / widgets rely on it .
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/assets/css/styles.css" /> <script src="https://cdn.jsdelivr.net/npm/inputmask@5.0.9/dist/inputmask.min.js"></script> <script type="module"> import * as EuroMod from "https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/browser/index.esm.js"; import { createEuroPlate } from "https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/client/index.mjs"; createEuroPlate(EuroMod, { wrapper: "#plateBox", i18n: "AUTO", autoFocusOnInit: false, deps: { inputmask: window.Inputmask }, // manual inject }); </script>
<script type="module"> import * as EuroMod from "https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/browser/index.esm.js"; import { createEuroPlate } from "https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/client/index.mjs"; createEuroPlate(EuroMod, { wrapper: "#plateBox", i18n: "AUTO", autoFocusOnInit: false, // No deps object โ will autoload Inputmask UMD from jsDelivr }); </script>
createEuroPlate(EuroMod, { wrapper: "#plateBox", cdn: { inputmask: "https://unpkg.com/inputmask@5.0.9/dist/inputmask.min.js" }, });
createEuroPlate(EuroMod, { wrapper: "#plateBox", autoLoadDeps: { inputmask: false }, });
<input id="myPlate" /> <script type="module"> import * as EuroMod from ".../index.esm.js"; import { createEuroPlate } from ".../index.mjs"; createEuroPlate(EuroMod, { input: document.getElementById("myPlate"), inputName: "plate_number", preserveInputAttrs: true, // do NOT overwrite existing id/name i18n: "EN", mode: "AUTO", autoFocusOnInit: false, }); </script>
add_action('wp_enqueue_scripts', function () { wp_register_script('epv-init', '', [], null, true); wp_enqueue_style( 'epv-styles', 'https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/assets/css/styles.css', [], '1.0.15' ); add_filter('script_loader_tag', function ($tag, $handle) { if ($handle === 'epv-init') { return '<script type="module">' . 'import * as EuroMod from "https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/browser/index.esm.js";' . 'import { createEuroPlate } from "https://cdn.jsdelivr.net/npm/@codecorn/euro-plate-validator@1.0.15/dist/client/index.mjs";' . 'window.__epvInit=(id,opts)=>createEuroPlate(EuroMod,Object.assign({wrapper:"#"+id,mode:"AUTO",i18n:"IT",debug:true,autoFocusOnInit:false},opts||{}));' . '</script>'; } return $tag; }, 10, 2); wp_enqueue_script('epv-init'); });
You can enqueue the CSS and auto-inject a window.__epvInit bootstrapper.
Then, create a shortcode to instantiate it dynamically inside Elementor.
Full example available in the Italian README โ "WordPress (WP) / Elementor" section.
npx @codecorn/euro-plate-validator "AB 123 CD" --countries IT,FR,DE --type car --prettyOptions:
--countries/-cโ comma-separated list of country codes--type/-tโcar,motorcycle, orany--pretty/-pโ human-readable output
Exit codes:
0โ valid1โ invalid2โ bad arguments
๐ฎ๐น IT | ๐ฌ๐ง UK | ๐ฉ๐ช DE | ๐ซ๐ท FR | ๐ช๐ธ ES | ๐ต๐น PT | ๐ณ๐ฑ NL | ๐ง๐ช BE | ๐จ๐ญ CH | ๐ฆ๐น AT | ๐ฎ๐ช IE | ๐ฑ๐บ LU ๐ฉ๐ฐ DK | ๐ธ๐ช SE | ๐ณ๐ด NO | ๐ซ๐ฎ FI | ๐ต๐ฑ PL | ๐จ๐ฟ CZ | ๐ธ๐ฐ SK | ๐ญ๐บ HU | ๐ท๐ด RO | ๐ง๐ฌ BG | ๐ธ๐ฎ SI | ๐ญ๐ท HR | ๐ฌ๐ท GR ๐ฑ๐น LT | ๐ฑ๐ป LV | ๐ช๐ช EE | ๐บ๐ฆ UA
-
Inputmask
- Safe merge of
definitions(no hard override of defaults). - New
Ltoken (letter) accepts lowercase and forces UPPERCASE (casing: "upper"). - Avoid redefining
A/9; useH(IT) /C(ES) only when needed. applyMaskNowapplied immediately on country change (no debounce race).- Finalized placeholders via
finalizeInputMaskLayouts+scripts/test-placeholders.mjs.
- Safe merge of
-
Client SDK
- Centralized logging (
imLog,imPreLog,imMounted,imError) usingBADGE/LOGwhendebug: true. - Lowercase input supported across layouts with
Ltoken. - Examples updated with
autoLoadDeps: { inputmask: true, jquery: true, toastr: true }anduseToastrLogger: true.
- Centralized logging (
-
Docs
- CDN bumped to 1.0.15.
- Notes about lowercase acceptance and uppercase coercion.
- Guidance to not override
A/9and define only custom tokens for restricted alphabets.
-
Status inline configurabile
statusMode: "inline" | "block" | "off"statusIcon: "none" | "icon" | "pill"showStatusText: booleaniconPosition: "left" | "right"
-
Riserva spazio automatica via
:has([data-state]) -
Nessuno stato su campo vuoto / parziale
-
Fix cambio paese (ITโFR) e Inputmask merge (
A/H/9) -
Refactor UI status (
setValidityUIunico writer) -
Add
clearStatusUI()per idle neutro
- NEW โ
autoFocusOnInit(default:false) โ prevents autofocus on init. - NEW โ
preserveInputAttrsโ keeps external inputid/nameintact. - UX โ renamed CSS classes from
.iti__*โ.epv__*. - Dependencies โ auto-loads
InputmaskUMD via CDN; supports manual injection and CDN override. - I18n โ IT / EN / AUTO (auto-detect from browser locale).
- UX stability โ dynamic placeholder, country-based formatter, debounce system.
- CSS/Assets consolidation.
- Added Client SDK + autoload fallback.
- Updated README, docs, and npm package.
MIT ยฉ CodeCornTM โ see LICENSE
Federico Girolami Full-Stack Developer โข System Integrator โข Digital Solution Architect ๐ ๐ codecorn.it ๐ง f.girolami@codecorn.it ๐ github.com/fgirolami29
Pull requests are welcome. For major changes, please open an issue first.
Powered by CodeCornTM ๐