Rumänische Adresse: Format, Regeln und ein React-Formular

Such nach „address form react“, und du bekommst ein US-Layout: Straße, Stadt, Bundesstaat, ZIP. Setzt du das Kunden in Rumänien vor, finden sie keinen Platz für Block, Treppenhaus oder den Sektor in Bukarest. Also ruft der Kurier an und fragt nach. Dieser Guide erklärt, wie eine rumänische Adresse aufgebaut ist, Teil für Teil, abgeglichen mit dem Merkblatt des Weltpostvereins (UPU) für Rumänien, mit englischen Labels und rumänischen Daten. Danach baut er das Formular in React mit Address Input, einer Komponente von Wingo UI, der Bibliothek, die wir bauen. Wir sind also nicht neutral.
Wie ist das Adressformat in Rumänien aufgebaut?
Eine rumänische Adresse läuft von der genauesten zur gröbsten Zeile: die Straßenzeile mit den Gebäudedetails, in Bukarest der Sektor, dann Postleitzahl und Ort. Das UPU-Merkblatt für Rumänien (opens in a new tab) (Stand Oktober 2007) nennt vier Regeln:
- Der Straßentyp steht vor dem Namen: Str. (strada), Bd. (bulevardul), Calea, Aleea, Șos. (șoseaua).
- Die Nummer beendet meist die Straßenzeile.
- Gebäudedetails können ans Ende derselben Zeile: Block, Treppenhaus, Etage, Wohnung.
- In Bukarest kann der Sektor in einer eigenen Zeile zwischen Straße und Ort stehen.
Die sechsstellige Postleitzahl steht links vom Ort. Hier zwei Beispiele aus dem Merkblatt, eine Wohnung in Bukarest und ein Büro in Craiova:
Das Merkblatt schreibt Valcii statt Vâlcii, und das spielt später bei der Suche eine Rolle. Beide Beispiele enden beim Ort, denn die Postleitzahl legt den Kreis schon fest. Bei Inlandspost, auf Rechnungen und in Kurierformularen ergänzt man den Kreis (județ) nach dem Ort als jud. Cluj. Das unterscheidet auch Dörfer mit gleichem Namen. So sieht die rumänische Postadresse als Formularfelder aus, mit englischen Labels:
Die Labels sind die englischen Standardwerte von Address Input. Die scară heißt bei uns „Entrance“, weil jedes Treppenhaus eines Blocks eine eigene Haustür hat, und genau die sucht der Kurier.
Wie schreibt man eine Adresse in Bukarest oder in einem Dorf?
In Bukarest ersetzt der Sektor den Kreis, und auf dem Land braucht ein Dorf meist auch seine Gemeinde. București ist ein Munizipium im Rang eines Kreises, aufgeteilt in sechs Sektoren. In einer Zeile geschrieben, so wie ein Kurierformular oder eine Rechnung sie druckt, endet eine Adresse in Bukarest mit „Sector 6, 061357 București“ und hat keinen jud.-Teil.
Dörfer bringen eine weitere Ebene mit. Kreise enthalten Munizipien (municipii), Städte (orașe) und Gemeinden (comune), und eine Gemeinde fasst mehrere Dörfer (sate) zusammen. Das Nationale Statistikinstitut führt die offizielle Liste als SIRUTA, ein Register auf diesen drei Ebenen, und veröffentlicht es als CSV auf data.gov.ro (opens in a new tab). Eine Dorfadresse nennt das Dorf und meist seine Gemeinde, etwa „sat Vâlcele, com. Feleacu, jud. Cluj“: Feleacu (opens in a new tab) ist eine Gemeinde mit fünf Dörfern, eines davon Vâlcele. In vielen ländlichen Gemeinden (opens in a new tab) gibt es überhaupt keine Straßennamen.
RoAddress, der Werttyp, hat kein Feld für die Gemeinde. Leg das Dorf in locality ab und seinen SIRUTA-Code in localityId: Das Register verknüpft jedes Dorf mit seiner Gemeinde, also kannst du die Gemeinde drucken, wenn ein Kurier sie braucht.
Wie hängen Postleitzahlen und Kreise in Rumänien zusammen?
Eine rumänische Postleitzahl verrät mit ihren ersten zwei Ziffern den Kreis, in Bukarest den Sektor. Rumänien hat am 1. Mai 2003 auf sechsstellige Codes umgestellt, und das UPU-Merkblatt liest sie als Postregion, einen Bezirk dieser Region (oder einen Sektor in Bukarest) und dann den Zustellbereich. Laut Wikipedia-Artikel zu den Postleitzahlen in Rumänien (opens in a new tab) bekommen Städte mit mehr als 50.000 Einwohnern einen Code pro Straße oder kleiner Adressgruppe, eine kleinere Stadt hat einen Code für die ganze Stadt, und Codes von Dörfern haben eine 7 als dritte Ziffer, wie 407270 für Feleacu. Die Postleitzahlensuche (opens in a new tab) von Poșta Română findet den vollständigen Code zu einer Adresse.
Hier die Liste der Kreise in Rumänien mit dem ISO-3166-2:RO (opens in a new tab)-Code (den Buchstaben auf den Kennzeichen) und dem Postleitzahl-Präfix. Address Input speichert den Kreis als diesen Code, und die Präfixe entsprechen seinen RO_POSTAL_PREFIXES:
Daraus ergibt sich eine Prüfung, die fast nichts kostet. Wählt jemand Iași und tippt einen Code, der mit 40 beginnt, stimmt eins von beiden nicht: postalCodeMatchesCounty("400114", "IS") liefert false. In Bukarest grenzt ein gewählter Sektor das auf ein Präfix ein, also ist postalCodeMatchesCounty("061357", "B", "6") true und derselbe Code mit Sektor "3" false.
Address Input zeigt eine Abweichung als gelbe Warnung unter der Postleitzahl, sobald das Feld den Fokus verliert, und das Formular bleibt gültig. Die Warnung ist Absicht: Die Prüfung kennt nur Präfixe, und wer seinen eigenen Code kennt, darf im Checkout nie hängen bleiben.
Wie baue ich ein rumänisches Adressformular in React?
Zerleg es in ein Kreis-Select, eine Ortssuche, Straße und Nummer, eine optionale Block-Zeile und eine sechsstellige Postleitzahl, dann validierst du beim Absenden und noch einmal auf dem Server. Address Input liefert diese Teile mit. Es ist eine Pro-Komponente, also meldest du dich einmal mit npx wingo-ui@latest login mit einem Pro-Konto an und führst dann npx wingo-ui@latest add address-input aus. Die CLI fügt alles hinzu, worauf die Komponente aufbaut, darunter ro-locations, text-match, das Select und die Combobox. Die Komponente rendert Kreis, Ort, Straße und Nummer, eine eingeklappte Zeile für Block, Treppenhaus, Etage und Wohnung, die Postleitzahl und ein Feld für Details wie die Gegensprechanlage oder einen Orientierungspunkt. Ihre Labels folgen dem Locale (erst der Prop locale, dann der Provider, dann die Sprache der Seite): Englisch, bei ro Rumänisch.
Ein Checkout-Schritt, der beim Absenden validiert und über die weiter unten gezeigte Server Action speichert:
showSummary gibt formatRoAddress unter dem Formular aus, so wie der Kurier die Adresse lesen wird: Str. Memorandumului 28, bl. A2, sc. 1, et. 3, ap. 12, 400114 Cluj-Napoca, jud. Cluj.
Was einem selbst gebauten Formular meist fehlt:
- Smartphones. Die Listen für Kreis und Ort öffnen sich unter 768px als Bottom Sheets, die Postleitzahl nimmt sechs Ziffern über die Zifferntastatur an, und Enter springt zum nächsten Teil.
- Autofill. Der Kreis nutzt
address-level1, der Ortaddress-level2, die Straßeaddress-line1und der Codepostal-code, also füllt eine im Browser gespeicherte Adresse die einzelnen Teile. - Einfügen. „Str. Memorandumului nr. 28, bl. A2“, in die Straße eingefügt, füllt Straße, Nummer und Block.
- Kreiswechsel. Wählst du București als Kreis, wird der Ort zu einem Sektor-Select. Ein Wechsel des Kreises leert den Ort und eine Postleitzahl aus einem anderen Kreis und behält Straße und Nummer.
$ npx wingo-ui@latest add address-inputWie suche ich Orte ohne Diakritika?
Normalisiere beide Strings, bevor du sie vergleichst: Kleinbuchstaben, Zerlegung mit NFD, dann die kombinierenden Zeichen entfernen. "Iași".includes("iasi") ergibt false, normalisiert lauten beide Seiten iasi. Ș und ț mit Komma darunter kamen erst 1999 mit Unicode 3.0, und ältere Kodierungen kannten nur die Cedille-Formen ş und ţ (opens in a new tab), die in importierten Daten immer noch auftauchen. Beide zerfallen in einen Grundbuchstaben plus ein kombinierendes Zeichen, also behandelt die NFD-Normalisierung Ștefănești, Ştefăneşti und stefanesti als denselben Namen.
text-match übernimmt diese Normalisierung, sortiert Treffer (exakt, Präfix, Wortanfang, innerhalb eines Worts) und liefert die Bereiche zum Hervorheben, in etwa 200 Zeilen ohne Abhängigkeiten. ro-locations baut seine searchLocations darauf auf, und die Orts-Combobox von Address Input filtert damit.
$ npx wingo-ui@latest add ro-locationsDie Normalisierung deckt keine Abkürzungen und keine alten Schreibweisen ab. Viele tippen „Tg. Mureș“ für Târgu Mureș, und Datensätze aus der Zeit vor der Rechtschreibregel von 1993 schreiben î mitten im Wort (Tîrgu). filterByText nimmt neben dem Label auch Schlüsselwörter an, Aliasse lösen also beide Fälle:
Jetzt finden „tg mures“ und „tirgu mures“ beide Târgu Mureș, etwas unter einem direkten Treffer auf den Namen einsortiert.
Wie lade ich alle Dörfer aus SIRUTA?
Stell die SIRUTA-Liste über eine eigene Route bereit und gib Address Input eine Funktion loadLocalities, die sie abfragt. Ohne sie durchsucht die Komponente eine eingebaute Liste mit 332 Munizipien, Städten und großen Gemeinden und nimmt jeden anderen Ort so an, wie er getippt wurde, mit einem dezenten Hinweis unter dem Feld. text-match hat keine "use client"-Direktive, also läuft dieselbe Suche in einem Route Handler:
Der value, den du zurückgibst, wird zu localityId, also wird der SIRUTA-Code mit der Adresse gespeichert.
Wie validiere ich die Adresse auf dem Server?
Prüf sie in der Server Action noch einmal, mit einem zod-4-Schema (npm install zod) in einer Datei ohne "use client". Kopierter Komponentencode hat hier eine Falle: address-input.tsx beginnt mit "use client", also ist auf dem Server jeder Export eine Client-Referenz. Rufst du validateRoAddress oder formatRoAddress in einer Server Component oder einer Server Action auf, wirft das „Attempted to call formatRoAddress() from the server but formatRoAddress is on the client“. Typ-Importe sind in Ordnung, und ro-locations hat keine Direktive, also kann das Schema dessen Kreis-Lookup nutzen:
Fehler aus der Action landen über den Prop errors beim passenden Teil und haben Vorrang vor den eigenen Fehlern der Komponente. Willst du eine Adresse für eine Bestell-E-Mail auf dem Server formatieren, verschieb formatRoAddress und seine Helfer in ein Modul ohne die Direktive. Der Quellcode gehört dir.
Was baue ich als Nächstes?
Probier die Postleitzahl-Prüfung in der Demo oben aus und bau das Formular dann mit npx wingo-ui@latest add address-input in deinen Checkout ein. Address Input und ro-locations gehören zu Wingo UI Pro ($8 im Monat, $80 im Jahr oder $150 einmalig, Stand Oktober 2026), text-match ist kostenlos. Nimmt derselbe Checkout auch Firmendaten auf, deckt die Validierung der rumänischen CUI die Steuernummern ab und der Guide zur IBAN-Prüfung die Bankkonten, während React Form Components den Aufbau aus Label, Hinweis und Fehler erklärt, den jeder Teil dieses Formulars teilt. Mehr React-Projekte Schritt für Schritt findest du in der Kategorie „Praxis: Screens und Apps“.
Häufige Fragen
Wie schreibt man eine Adresse in Rumänien?
Zuerst kommen Straßentyp, Name und Nummer (Str. Memorandumului 28), dann Block, Treppenhaus, Etage und Wohnung in derselben Zeile (bl. A2, sc. 1, et. 3, ap. 12). Die nächste Zeile enthält die sechsstellige Postleitzahl und den Ort (400114 Cluj-Napoca), im Inland gefolgt vom Kreis als jud. Cluj, und in Bukarest steht eine Zeile mit dem Sektor über der Postleitzahl. Post aus dem Ausland endet mit ROMANIA in einer eigenen Zeile.
Wie viele Stellen hat eine rumänische Postleitzahl?
Sechs. Die sechsstelligen Codes haben am 1. Mai 2003 die vierstelligen ersetzt. Die ersten zwei Ziffern stehen für den Kreis, in Bukarest für den Sektor, von 01 für Sektor 1 bis 06 für Sektor 6.
Was bedeuten bl., sc., et. und ap. in einer rumänischen Adresse?
Sie kürzen bloc (das Wohnhaus), scară (das Treppenhaus mit eigenem Eingang), etaj (die Etage) und apartament (die Wohnung) ab. Das Erdgeschoss heißt parter.
Wie viele Kreise hat Rumänien?
Rumänien hat 41 Kreise (județe) plus das Munizipium Bukarest, das in sechs Sektoren aufgeteilt ist. Ihre ISO-3166-2:RO-Codes, etwa RO-CJ für Cluj und RO-B für Bukarest, nutzen dieselben Buchstaben wie die rumänischen Kennzeichen.
Sollte ein rumänisches Adressformular Diakritika verlangen?
Nein. Nimm an, was die Leute tippen, und vergleiche ohne Diakritika: Schon die Beispieladressen der UPU für Rumänien sind ohne sie geschrieben, und ältere Daten nutzen die Cedille-Formen ş und ţ. Speichere die offizielle Schreibweise aus deiner Ortsliste, sobald jemand einen Treffer auswählt.
Sind Address Input und die rumänischen Ortsdaten kostenlos?
Address Input und ro-locations gehören zu Wingo UI Pro. text-match, die diakritikunabhängige Suche, die beide nutzen, ist kostenlos und lässt sich mit npx wingo-ui@latest add text-match installieren.
- Rumänien
- Adressformular
- React
- Postleitzahlen
- Formulare
- Next.js


