Zum Inhalt springen
    WingoUI
    KomponentenVorlagenDokuPreiseKI-AgentenBlogChangelog
    1. Startseite
    2. Blog
    3. Komponenten-Guides
    4. IBAN prüfen JavaScript: Mod 97, Regex und ein React-Feld
    Read in English
    1. Blog
    2. Komponenten-Guides
    3. IBAN prüfen JavaScript: Mod 97, Regex und ein React-Feld
    Komponenten-Guides
    Komponenten-Guides

    IBAN prüfen JavaScript: Mod 97, Regex und ein React-Feld

    SR
    Serban Rusu · Gründer von Wingo UI
    9. Okt. 2026 · 11 Min. Lesezeit

    Auf dieser Seite

    0%
    1. Warum reicht ein Regex nicht, um eine IBAN zu prüfen?
    2. Wie funktioniert der Mod-97-Check der IBAN?
    3. Wie prüfe ich eine IBAN in TypeScript?
    4. Wie ist die rumänische IBAN aufgebaut?
    5. Wie baue ich ein IBAN-Feld, das beim Tippen formatiert?
    6. Wie zeige ich eine IBAN so an, dass man sie kopieren kann?
    7. Heißt eine gültige IBAN, dass das Konto existiert?
    8. Sollte ich stattdessen eine Bibliothek wie ibantools nehmen?
    9. Sollte ich diesen Code kopieren oder installieren?
    10. Häufige Fragen
      1. Wie prüfe ich eine IBAN in JavaScript?
      2. Wie sieht der Regex für eine IBAN aus?
      3. Wie viele Zeichen hat eine rumänische IBAN?
      4. Heißt eine gültige IBAN, dass das Konto existiert?
      5. Warum lehnt mein IBAN-Check gültige IBANs ab?
      6. Wie finde ich die Bank zu einer rumänischen IBAN?

    Kurz gesagt

    Um eine IBAN in JavaScript zu prüfen, entfernst du die Leerzeichen, wandelst sie in Großbuchstaben um, prüfst die Länge für ihr Land, verschiebst die ersten vier Zeichen ans Ende, machst aus jedem Buchstaben zwei Ziffern (A ist 10, Z ist 35) und prüfst, ob die ganze Zahl mod 97 gleich 1 ist. Den Rest trägst du Zeichen für Zeichen weiter, denn die Zahl hat mehr Stellen, als der Typ Number in JavaScript exakt darstellen kann. Eine gültige IBAN ist korrekt aufgebaut, beweist aber nicht, dass das Konto existiert.

    Veröffentlicht am 9. Okt. 2026

    Deine Auszahlungseinstellungen, dein Lieferantenformular oder deine Rechnungsvorlage fragen nach einem Bankkonto, und die Leute fügen IBANs in jeder Form ein: kleingeschrieben, in Vierergruppen, mit Bindestrichen, mit den geschützten Leerzeichen aus einem PDF, manchmal mit „IBAN:“ davor. Viele Snippets zum Thema „IBAN prüfen JavaScript“ hören bei einem Regex auf, der eine vertippte Ziffer durchlässt, oder rufen parseInt auf und lehnen damit gültige Konten ab. In diesem Tutorial schreiben wir den Mod-97-Check in TypeScript, bauen ihn in eine zod-Regel und ein React-Feld ein, das beim Tippen formatiert, lesen die Bank aus rumänischen IBANs aus und zeigen das Ergebnis mit einem Copy-Button an. Die UI nutzt Masked Input (Pro), Input und Copy Button (beide kostenlos) aus Wingo UI, der Bibliothek, die wir bauen. Wir sind also nicht neutral. Der Validator ist reines TypeScript, das du überall einfügen kannst.

    Warum reicht ein Regex nicht, um eine IBAN zu prüfen?

    Ein Regex prüft die Form, und ein Tippfehler behält die Form. Wer nach „IBAN Regex“ sucht, findet meist diesen Ausdruck. Du wendest ihn an, nachdem du die Leerzeichen entfernt und alles in Großbuchstaben umgewandelt hast:

    ts
    const IBAN_SHAPE = /^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/;

    Zwei Buchstaben für das Land, zwei Prüfziffern, dann 11 bis 30 Buchstaben oder Ziffern, denn IBANs reichen von 15 Zeichen (Norwegen) bis maximal 34. Ein Länder-Pattern ist strenger: Das für Rumänien lautet ^RO\d{2}[A-Z]{4}[A-Z0-9]{16}$. Beide akzeptieren RO49AAAA1B31007593840001, also die rumänische Beispiel-IBAN aus dem IBAN-Register mit geänderter letzter Ziffer.

    Genau dafür gibt es die zwei Prüfziffern. Jeder String in der rumänischen Form besteht den Regex, aber nur etwa 1 von 97 zufälligen Strings besteht mod 97: In einem Lauf mit 200.000 zufälligen Strings war es etwa 1 %. Behalte den Regex trotzdem, als ersten von drei Checks. So kann deine Meldung „das ist keine IBAN“ sagen, bevor sie „diese IBAN hat einen Tippfehler“ sagt.

    Wie funktioniert der Mod-97-Check der IBAN?

    Das Verfahren heißt kurz IBAN mod 97: Verschieb die ersten vier Zeichen ans Ende, ersetz jeden Buchstaben durch zwei Ziffern (A ist 10, B ist 11, bis Z mit 35), lies das Ergebnis als eine einzige Ganzzahl und teil sie durch 97. Bei einer gültigen IBAN bleibt der Rest 1. Der IBAN-Artikel auf Wikipedia (opens in a new tab) beschreibt diese Schritte aus ISO 13616. Wer die IBAN vergibt, berechnet die Prüfziffern als 98 minus den Rest derselben Zahl mit 00 an ihrer Stelle. Deshalb landet eine gültige IBAN bei 1.

    Hier die britische Beispiel-IBAN, von Hand durchgerechnet:

    SchrittWert
    Leerzeichen entfernenGB29NWBK60161331926819
    Erste vier Zeichen ans Ende verschiebenNWBK60161331926819GB29
    Buchstaben in Zahlen (N 23, W 32, B 11, K 20, G 16)2332112060161331926819161129
    Rest mod 971

    Diese Ganzzahl hat 28 Stellen, und der JavaScript-Typ Number ist nur bis 2^53 exakt, und 2^53 hat 16 Stellen. Number(digits) % 97 und parseInt(digits, 10) % 97 liefern für diese IBAN beide 5 und lehnen damit ein gültiges Konto ab. BigInt(digits) % 97n funktioniert. Den Rest Zeichen für Zeichen weiterzutragen funktioniert auch und spart die Umwandlung in einen Ziffern-String.

    Laut Wikipedia erkennt der Check jedes einzelne falsche Zeichen und alle oder fast alle Vertauschungen benachbarter Zeichen. Wir haben das getestet. Bei 2.000 zufälligen deutschen IBANs, die nach dem Ländercode nur aus Ziffern bestehen, fiel jede geänderte Ziffer und jede Vertauschung zweier Nachbarn durch den Check. Buchstaben schwächen den Check: Bei 2.000 zufälligen IBANs im rumänischen Stil mit Buchstaben im Kontoteil haben etwa 0,35 % der Änderungen eines einzelnen Zeichens und der Nachbarvertauschungen trotzdem bestanden, ungefähr 1 von 300, denn ein Buchstabe wird zu zwei Ziffern. Machst du im Registerbeispiel aus 1B ein B1, ergeben beide 111, und RO49AAAAB131007593840000 besteht.

    Wie prüfe ich eine IBAN in TypeScript?

    Willst du eine IBAN validieren, normalisier die Eingabe und lass dann drei Checks in dieser Reihenfolge laufen: die Form, die Länge für das Land und mod 97. Gib zurück, welcher Check gescheitert ist. Dann kann das Formular das Problem erklären, statt nur „ungültig“ zu melden:

    ts
    // lib/iban.ts
    // die 42 IBAN-Ländercodes in den SEPA-Verfahren (EPC, August 2026), mit ihren
    // Längen aus dem IBAN Registry von SWIFT, wie ibantools 4.5.4 sie mitliefert
    const LENGTHS: Record<string, number> = Object.fromEntries(
    (
    "AD24 AL28 AT20 BE16 BG22 CH21 CY28 CZ24 DE22 DK18 EE20 ES24 FI18 FR27 " +
    "GB22 GI23 GR27 HR21 HU28 IE22 IS26 IT27 LI21 LT20 LU20 LV21 MC27 MD24 " +
    "ME22 MK19 MT31 NL18 NO15 PL28 PT25 RO24 RS22 SE24 SI19 SK24 SM27 VA22"
    )
    .split(" ")
    .map((entry) => [entry.slice(0, 2), Number(entry.slice(2))]),
    );
    export type IbanProblem = "format" | "country" | "length" | "checksum";
    export const ibanLength = (country: string) => LENGTHS[country.toUpperCase()];
    // " iban: ro49 aaaa-1b31 ..." -> "RO49AAAA1B31..."; \s deckt auch die geschützten Leerzeichen aus PDFs ab
    export function electronicIban(input: string): string {
    return input.trim().toUpperCase().replace(/^IBAN:?/, "").replace(/[\s.-]/g, "");
    }
    // der Rest der umgestellten IBAN, Zeichen für Zeichen, damit die Zahl nie über einen Float hinauswächst
    function mod97(iban: string): number {
    const rearranged = iban.slice(4) + iban.slice(0, 4);
    let remainder = 0;
    for (const char of rearranged) {
    // A ist 10 ... Z ist 35: ein Buchstabe bringt zwei Ziffern, also um 100 verschieben
    const value = char >= "A" ? char.charCodeAt(0) - 55 : Number(char);
    remainder = (remainder * (value > 9 ? 100 : 10) + value) % 97;
    }
    return remainder;
    }
    export function checkIban(input: string): { iban: string; problem: IbanProblem | null } {
    const iban = electronicIban(input);
    if (!/^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/.test(iban)) return { iban, problem: "format" };
    const length = ibanLength(iban.slice(0, 2));
    if (!length) return { iban, problem: "country" };
    if (iban.length !== length) return { iban, problem: "length" };
    return { iban, problem: mod97(iban) === 1 ? null : "checksum" };
    }
    export const isValidIban = (input: string) => checkIban(input).problem === null;
    // "RO49AAAA1B31007593840000" -> "RO49 AAAA 1B31 0075 9384 0000"
    export const formatIban = (input: string) => electronicIban(input).replace(/(.{4})(?=.)/g, "$1 ");
    // Prüfziffern für Testdaten: ibanCheckDigits("GB", "NWBK60161331926819") -> "29"
    export function ibanCheckDigits(country: string, bban: string): string {
    return String(98 - mod97(`${country}00${bban}`)).padStart(2, "0");
    }
    ts
    checkIban("gb29-nwbk-6016-1331-9268-19"); // { iban: "GB29NWBK60161331926819", problem: null }
    checkIban("IBAN: RO49 AAAA 1B31 0075 9384 0001"); // problem: "checksum"
    checkIban("US12345678901234567"); // problem: "country"
    formatIban("ro49aaaa1b31007593840000"); // "RO49 AAAA 1B31 0075 9384 0000"
    ibanCheckDigits("RO", "BTRL0123456789ABCDEF"); // "17", also besteht RO17BTRL0123456789ABCDEF

    Vier Entscheidungen aus dieser Datei solltest du übernehmen, auch wenn du den Rest neu schreibst:

    • Zuerst in Großbuchstaben umwandeln. "n".charCodeAt(0) - 55 ergibt 55, "N" dagegen 23. Ohne diesen Schritt scheitert also jede kleingeschriebene IBAN.
    • Jede Art von Leerzeichen entfernen. \s in einem JavaScript-Regex erfasst auch die geschützten und schmalen Leerzeichen, die PDFs und Banking-Apps zwischen die Gruppen setzen.
    • Länder ablehnen, in die du nicht auszahlst. Die Tabelle enthält die 42 IBAN-Ländercodes aus der Übersicht der SEPA-Teilnehmer des EPC vom August 2026 (opens in a new tab), Albanien, Moldau, Montenegro, Nordmazedonien und Serbien eingeschlossen. Alles andere bekommt "country", die ehrliche Antwort für ein SEPA-Auszahlungsformular. Wenn du IBANs aus allen Ländern annimmst, nimm eine Bibliothek (siehe den letzten Abschnitt).
    • Testdaten erzeugen. ibanCheckDigits baut aus jedem Land und jedem Kontoteil eine gültige IBAN. So enthalten deine Fixtures nie das Konto einer echten Person.

    Wie ist die rumänische IBAN aufgebaut?

    Eine rumänische IBAN hat 24 Zeichen: RO, zwei Prüfziffern, vier Buchstaben für die Bank und 16 Buchstaben oder Ziffern für Filiale und Konto. Die vier Bankbuchstaben sind die ersten vier Zeichen des BIC der Bank, also ihres SWIFT-Codes. BTRL steht demnach für Banca Transilvania (BIC BTRLRO22). Die Tabelle IBAN formats by country (opens in a new tab) auf Wikipedia notiert das Format als RO kk bbbb cccc cccc cccc cccc.

    PositionenRegisterbeispielBedeutung
    1 bis 2ROLand
    3 bis 449Prüfziffern
    5 bis 8AAAABank, die ersten vier Zeichen ihres BIC
    9 bis 241B31 0075 9384 0000Filiale und Konto, Buchstaben erlaubt

    Daraus folgen zwei Regeln. Eine Regel „nach dem Bankcode nur Ziffern“ lehnt echte rumänische Konten ab, denn der Kontoteil darf Buchstaben enthalten: IBANs der Banca Transilvania zum Beispiel enthalten direkt nach dem Bankcode Buchstaben wie RONCRT. Und die Bank findest du mit einem einzigen Lookup:

    ts
    // lib/iban.ts (Fortsetzung)
    // die vier Buchstaben nach den Prüfziffern sind der Anfang des BIC der Bank
    const RO_BANKS: Record<string, string> = {
    BTRL: "Banca Transilvania",
    RNCB: "BCR",
    BRDE: "BRD",
    INGB: "ING Bank",
    RZBR: "Raiffeisen Bank",
    BACX: "UniCredit Bank",
    CECE: "CEC Bank",
    TREZ: "Staatskasse",
    };
    export function romanianBank(input: string): string | null {
    const iban = electronicIban(input);
    return iban.startsWith("RO") ? (RO_BANKS[iban.slice(4, 8)] ?? null) : null;
    }
    ts
    romanianBank("RO17 BTRL 0123 4567 89AB CDEF"); // "Banca Transilvania"
    romanianBank("GB29 NWBK 6016 1331 9268 19"); // null

    Zeig den Namen als Hinweis, den die Person wiedererkennt. Er beweist nichts über das Konto, und die Tabelle ist eine Momentaufnahme von Banken, die fusionieren. Als OTP Bank Rumänien Anfang 2025 in der Banca Transilvania aufging, bekamen ihre Kunden neue BTRL-IBANs, und die Banca Transilvania schickte Arbeitgebern die neuen IBANs für Gehälter ab März 2025 (opens in a new tab). Eine alte OTP-IBAN besteht mod 97 trotzdem.

    Wie baue ich ein IBAN-Feld, das beim Tippen formatiert?

    Nimm ein maskiertes Feld, das den Rohwert getrennt vom angezeigten Text speichert. Das Preset iban von Masked Input wandelt beim Tippen in Großbuchstaben um, gruppiert in Vierergruppen, hält den Cursor direkt hinter dem getippten Zeichen und entfernt Trennzeichen aus eingefügtem Text. Sobald die IBAN vollständig ist, lässt es mod 97 laufen und blendet ein Häkchen oder ein Warnsymbol ein; der rote Ring und aria-invalid warten, bis du das Feld verlässt. Auf Smartphones behält es mit autoCapitalize="characters" die Texttastatur, denn ein Ziffernblock hat keine Buchstaben für den Ländercode.

    Tipp oder füg gb29-nwbk-6016-1331-9268-19 ein: Das Feld wandelt in Großbuchstaben um, gruppiert in Vierergruppen und zeigt ein Häkchen. Änderst du die letzte Ziffer, wird aus dem Häkchen eine Warnung
    $ npx wingo-ui@latest add masked-input
    ProDoku: Masked Input

    Das Preset bringt Längen für neun Länder mit: Rumänien, Moldau, Deutschland, Großbritannien, Frankreich, Italien, Spanien, Bulgarien und Ungarn. Für jedes andere Land gruppiert es weiterhin in Vierergruppen, wartet aber auf 34 Zeichen, bevor es prüft. Eine niederländische IBAN bekommt ihr Symbol also nie. Übergib eine Maske, die sich aus derselben Tabelle berechnet wie dein Validator. Das Preset behält dabei die Umwandlung in Großbuchstaben und seine Tastatureinstellungen:

    ts
    // lib/iban-mask.ts
    import { ibanLength } from "@/lib/iban";
    // "AA99 **** **** ..." passend zum Land, damit das Feld weiß, wann die IBAN vollständig ist
    export function ibanMask(raw: string): string {
    const length = ibanLength(raw.slice(0, 2)) ?? 34;
    let mask = "AA99";
    for (let i = 4; i < length; i++) mask += (i % 4 === 0 ? " " : "") + "*";
    return mask;
    }

    Die zod-Regel macht aus jedem gescheiterten Check eine eigene Meldung und gibt deiner Datenbank das elektronische Format ohne Leerzeichen:

    ts
    // lib/iban-schema.ts
    import { z } from "zod";
    import { checkIban, electronicIban, type IbanProblem } from "@/lib/iban";
    const MESSAGES: Record<IbanProblem, string> = {
    format: "Gib die vollständige IBAN ein, beginnend mit dem Ländercode, etwa GB29 NWBK 6016 1331 9268 19",
    country: "Wir können nur an Banken in SEPA-Ländern auszahlen",
    length: "Diese IBAN ist für ihr Land zu kurz oder zu lang",
    checksum: "Diese IBAN enthält einen Tippfehler: Die Prüfziffern passen nicht",
    };
    export const iban = z
    .string()
    .trim()
    .min(1, { error: "Gib deine IBAN ein", abort: true })
    .check((ctx) => {
    const { problem } = checkIban(ctx.value);
    if (problem) ctx.issues.push({ code: "custom", message: MESSAGES[problem], input: ctx.value });
    })
    .transform(electronicIban);

    Binde sie mit Controller von React Hook Form an, denn das Input-Element hält den maskierten Text und onValueChange liefert dir den Rohwert. Mit validate={isValidIban} sind sich das Symbol im Feld und die zod-Regel bei jeder IBAN einig:

    tsx
    "use client";
    import { Controller, useForm } from "react-hook-form";
    import { zodResolver } from "@hookform/resolvers/zod";
    import { z } from "zod";
    import { Button } from "@/components/ui/button";
    import { Input } from "@/components/ui/input";
    import { MaskedInput } from "@/components/ui/masked-input";
    import { electronicIban, isValidIban, romanianBank } from "@/lib/iban";
    import { ibanMask } from "@/lib/iban-mask";
    import { iban } from "@/lib/iban-schema";
    const schema = z.object({
    holder: z.string().trim().min(1, { error: "Gib den Namen des Kontoinhabers ein" }),
    iban,
    });
    type Values = z.output<typeof schema>;
    export function PayoutForm({ onSave }: { onSave: (values: Values) => Promise<void> }) {
    const form = useForm<z.input<typeof schema>, unknown, Values>({
    resolver: zodResolver(schema),
    // der erste Fehler wartet auf blur, danach prüft das Feld bei jedem Tastendruck neu
    mode: "onTouched",
    defaultValues: { holder: "", iban: "" },
    });
    const { errors, isSubmitting } = form.formState;
    return (
    <form noValidate onSubmit={form.handleSubmit(onSave)} className="flex flex-col gap-4">
    <Input label="Kontoinhaber" autoComplete="name" {...form.register("holder")} error={errors.holder?.message} />
    <Controller
    control={form.control}
    name="iban"
    render={({ field, fieldState }) => (
    <MaskedInput
    preset="iban"
    mask={ibanMask}
    validate={isValidIban}
    label="IBAN"
    placeholder="GB29 NWBK 6016 1331 9268 19"
    ref={field.ref}
    value={field.value}
    onValueChange={(raw) => field.onChange(raw)}
    onBlur={field.onBlur}
    // die Maske behält Buchstaben, also würde ein eingefügtes "IBAN:" zum Ländercode
    onPaste={(event) => {
    const text = event.clipboardData.getData("text");
    if (!/^\s*iban\b/i.test(text)) return;
    event.preventDefault();
    field.onChange(electronicIban(text));
    }}
    // eine rumänische IBAN nennt ihre Bank, sobald der Bankcode da ist
    description={romanianBank(field.value) ?? "Füg sie mit oder ohne Leerzeichen ein."}
    error={fieldState.error?.message}
    />
    )}
    />
    <Button type="submit" loading={isSubmitting}>
    Auszahlungsdaten speichern
    </Button>
    </form>
    );
    }

    Die Beschreibung zeigt „Banca Transilvania“, sobald jemand RO17BTRL tippt. So kann die Person schnell bestätigen, dass sie das richtige Konto kopiert hat. Der onPaste-Handler deckt den einen Fall beim Einfügen ab, den die Maske nicht bereinigen kann. Das Feld verwirft jedes Trennzeichen, behält aber Buchstaben. Ein aus einem Kontoauszug kopiertes „IBAN: RO17 BTRL ...“ würde also zu IB17 BTRL ... werden und mit der Länder-Meldung scheitern. Der Handler entfernt das Label mit electronicIban, bevor die Maske den Text sieht.

    Wenn du die Regel nicht selbst schreiben willst: Die Pro-Lib form-validation hat createValidators().iban(), mit einer einzigen Meldung für jeden Fehler und ohne Länderbeschränkung.

    Wie zeige ich eine IBAN so an, dass man sie kopieren kann?

    Zeig sie in Vierergruppen an und kopier sie ohne Leerzeichen. Die Gruppen helfen beim Vorlesen oder beim Abgleich mit einer Papierrechnung. In die Zwischenablage gehört das elektronische Format, denn eine IBAN mit 34 Zeichen wächst mit Leerzeichen auf 42 Zeichen, und ein Bankformular mit maxLength={34} schneidet beim Einfügen das Ende ab.

    tsx
    import { CopyButton } from "@/components/ui/copy-button";
    import { electronicIban, formatIban, romanianBank } from "@/lib/iban";
    export function PayoutAccount({ iban }: { iban: string }) {
    const bank = romanianBank(iban);
    return (
    <div className="flex items-center justify-between gap-3 rounded-2xl bg-surface p-4">
    <div className="min-w-0">
    <p className="font-mono text-sm">{formatIban(iban)}</p>
    {bank && <p className="text-xs text-muted-foreground">{bank}</p>}
    </div>
    <CopyButton value={electronicIban(iban)} copyLabel="IBAN kopieren" />
    </div>
    );
    }

    Copy Button rendert einen Icon-Button mit dem Label „IBAN kopieren“. Auf dem Desktop wechselt sein Tooltip zu „Copied“; auf dem Smartphone geben das Häkchen, eine kurze Vibration und eine Ansage für Screenreader das Feedback, und die kleine Größe behält auf Touch-Geräten eine Trefferfläche von 44px. Die gruppierte IBAN bricht an ihren Leerzeichen um und schiebt die Zeile so nie über die Breite eines 360px-Bildschirms hinaus.

    Heißt eine gültige IBAN, dass das Konto existiert?

    Nein. Die Prüfziffern beweisen, dass die IBAN korrekt aufgebaut ist. Ein geschlossenes Konto, ein Konto bei einer inzwischen fusionierten Bank und das Konto der falschen Person bestehen den Check alle. Den letzten Fall fängt der Name des Kontoinhabers ab. Nach der EU-Verordnung über Sofortzahlungen müssen Banken die Empfängerüberprüfung (Verification of Payee) anbieten. Sie vergleicht vor einer Überweisung den Namen des Empfängers mit dem Konto und liefert ein Ergebnis wie Übereinstimmung, teilweise Übereinstimmung oder keine Übereinstimmung. Die Übersicht der EZB zur Verordnung (opens in a new tab) nennt den 9. Oktober 2025 für den Euroraum und den 9. Juli 2027 für die Mitgliedstaaten ohne Euro, Rumänien eingeschlossen.

    Dieser Check läuft bei der Bank des Zahlers, wenn das Geld abgeht, lange nachdem dein Formular abgeschickt wurde. Prüf also die Ziffern, während die Leute tippen, und frag neben der IBAN nach dem Namen des Kontoinhabers, wie es das Formular oben tut. Dann hat die Bank einen Namen zum Vergleichen.

    Sollte ich stattdessen eine Bibliothek wie ibantools nehmen?

    Nimm eine, wenn du IBANs aus allen Ländern annimmst. Stand Oktober 2026 bringt ibantools (opens in a new tab) 4.5.4 (veröffentlicht im April 2026, MIT oder MPL-2.0) die Länge und das Kontomuster jedes Registerlandes mit, validateIBAN liefert Fehlercodes, die du auf Meldungen abbilden kannst, und isValidBIC prüft SWIFT-Codes. Es prüft auch die nationalen Prüfziffern, die manche Länder im Kontoteil ergänzen, etwa Belgien, Spanien und Frankreich. Die Datei oben lässt diese aus. Ein Haken für ein SEPA-Formular: isSEPACountry liefert in 4.5.4 für Albanien, Moldau, Montenegro, Nordmazedonien und Serbien noch false. Das Paket iban (opens in a new tab), die andere übliche Antwort, wurde zuletzt im Februar 2020 veröffentlicht. Für ein reines SEPA-Formular deckt die Datei oben Form, Länge und mod 97 ohne Abhängigkeit ab, und du kannst jede Zeile davon lesen.

    Sollte ich diesen Code kopieren oder installieren?

    Kopier ihn, wenn du ein einziges einfaches Feld brauchst: lib/iban.ts, die zod-Regel und der kostenlose Input reichen dafür. In Wingo UI Pro ist Masked Input das Feld aus der Demo, und die Lib invoicing exportiert isValidIban (Längen für 19 Länder, jedes andere Land bekommt Form und mod 97), formatIban, getIbanBank und eine Tabelle RO_BANKS mit 19 rumänischen Bankcodes, neben den Checks aus unserem Guide zur rumänischen CUI-Validierung und unserem rumänischen CNP-Validator. Die Pläne findest du auf der Preisseite. Installier das Feld und den kostenlosen Copy-Button mit npx wingo-ui@latest add masked-input copy-button. Für den Rest der Formular-Anatomie lies React Form Components: barrierefreie Felder, zod und Mobile oder stöber in weiteren Komponenten-Guides.

    Komponenten in diesem Artikel

    • Masked Input

      A React masked input that formats itself as you type or paste: card number, expiry, CVC, IBAN, CNP, postal code or a custom mask.

      Pro
    • Invoicing

      Invoice math for React billing apps: VAT per rate the way e-Factura checks it, Romanian VAT rates, and CUI, IBAN and CNP validation.

      Pro
    • Copy Button

      A React copy to clipboard button for IBANs, tax IDs, links and API keys: an icon button with a tooltip, a labelled button and CopyText.

      Free
    • Input

      A React text input: icons and addons inside the box, a clear button, a loading spinner, a character counter and floating labels.

      Free
    • Form validation

      Zod validation rules for React forms with one message set (English or Romanian), react-hook-form glue and a pretend request.

      Pro

    Häufige Fragen

    Wie prüfe ich eine IBAN in JavaScript?

    Entferne Leerzeichen und Bindestriche, wandle den String in Großbuchstaben um und prüf die Länge für das Land. Dann verschiebst du die ersten vier Zeichen ans Ende, ersetzt jeden Buchstaben durch seine Zahl (A ist 10, Z ist 35) und berechnest den Rest mod 97 Ziffer für Ziffer; die IBAN ist gültig, wenn der Rest 1 ist.

    Wie sieht der Regex für eine IBAN aus?

    Nachdem du die Leerzeichen entfernt und alles in Großbuchstaben umgewandelt hast, passt /^[A-Z]{2}\d{2}[A-Z0-9]{11,30}$/ auf die Form jeder IBAN, und ein Länder-Pattern wie ^RO\d{2}[A-Z]{4}[A-Z0-9]{16}$ prüft zusätzlich die Länge. Keiner von beiden testet die Prüfziffern, also lass nach dem Regex noch mod 97 laufen.

    Wie viele Zeichen hat eine rumänische IBAN?

    24: RO, zwei Prüfziffern, vier Buchstaben für die Bank (die ersten vier Zeichen ihres BIC) und 16 Buchstaben oder Ziffern für Filiale und Konto, zum Beispiel RO49 AAAA 1B31 0075 9384 0000.

    Heißt eine gültige IBAN, dass das Konto existiert?

    Nein. Die Prüfziffern beweisen nur, dass die IBAN korrekt aufgebaut ist, also besteht auch ein geschlossenes Konto oder das Konto der falschen Person den Test. In der EU vergleicht die Empfängerüberprüfung (Verification of Payee) bei der Bank des Zahlers den Namen des Empfängers mit dem Konto, bevor eine Überweisung ausgeführt wird, ab dem 9. Oktober 2025 im Euroraum und ab dem 9. Juli 2027 in Rumänien und den anderen Mitgliedstaaten ohne Euro.

    Warum lehnt mein IBAN-Check gültige IBANs ab?

    Oft liegt es an Number oder parseInt: Die umgestellte IBAN hat mehr Ziffern, als der Typ Number in JavaScript exakt darstellen kann, also kommt ein falscher Rest heraus. Kleinbuchstaben, aus einem PDF eingefügte geschützte Leerzeichen und ein vorangestelltes „IBAN:“ sind die anderen üblichen Verdächtigen.

    Wie finde ich die Bank zu einer rumänischen IBAN?

    Lies die Zeichen 5 bis 8. Sie sind die ersten vier Zeichen des BIC der Bank, also steht BTRL für Banca Transilvania und RNCB für BCR. Halte deine Tabelle aktuell, denn fusionierte Banken hinterlassen alte Codes.

    • IBAN
    • Formularvalidierung
    • TypeScript
    • React
    • Rumänien
    • Zahlungen

    Teilen

    SR

    Über den Autor

    Serban Rusu

    Gründer von Wingo UI

    Serban Rusu hat Wingo UI gegründet. Er baut die Komponenten, die CLI und den MCP-Server und schreibt über React-UIs für Smartphones und KI-Agents.

    Mehr von Serban
    Weiterlesen

    Ähnliche Artikel

    Alle Artikel
    Komponenten-Guides

    CNP prüfen: rumänische Personennummer in TypeScript und Zod

    CNP prüfen in TypeScript: die gewichtete Prüfziffer, echte Geburtsdaten, der neue Kreiscode 70, eine zod-Regel, ein React-Feld und sicheres Speichern.

    SRSerban Rusu·9. Okt. 2026·13 Min. Lesezeit
    Komponenten-Guides

    CUI prüfen: rumänische Steuer-ID mit TypeScript und Zod

    CUI prüfen in TypeScript: die Prüfziffer mit dem Schlüssel 753217532 Schritt für Schritt, das Präfix RO, eine zod-Regel, ein React-Feld und die ANAF-Abfrage.

    SRSerban Rusu·9. Okt. 2026·10 Min. Lesezeit
    Komponenten-Guides

    React Form Components: barrierefrei, mit Zod und mobil

    React Form Components mit einer Anatomie (Label, Hinweis, Fehler, Zähler), angebunden an react-hook-form und zod und fürs Smartphone gebaut, mit vollem Code.

    SRSerban Rusu·9. Okt. 2026·25 Min. Lesezeit
    Newsletter

    Neue Artikel per E-Mail

    Neue Guides, Tutorials und Vergleiche aus dem Wingo UI Blog, sobald sie erscheinen. Die meisten Artikel sind auf Englisch.

    Kein Spam. Du kannst dich jederzeit abmelden.

    WingoUI

    Animierte, konfigurierbare, mobile-first React-Komponenten und Blöcke. Kopier den Quellcode, pass ihn an und lass deinen Coding-Agenten damit bauen.

    Produkt

    • Komponenten
    • Vorlagen
    • Preise
    • KI-Agenten
    • Theme-Generator

    Ressourcen

    • Doku
    • Blog
    • Changelog
    • Changelog-RSS
    • llms.txt

    Rechtliches

    • AGB
    • Datenschutz
    • Rückerstattung
    • Lizenz
    • Impressum

    Komponenten-Kategorien

    • Buttons & Actions
    • Inputs
    • Forms
    • Navigation
    • Overlays
    • Feedback
    • Data Display
    • Tables & Lists
    • Charts & Stats
    • Layout
    • Media
    • AI Kit
    • Text & Effects
    • Mobile
    • Commerce
    • Marketing Sections
    • Blocks
    • Hooks & Utilities

    © 2026 Wingo UI

    Wingo UI