Semantisches HTML · Interaktive & Medien-Elemente
Formular-Semantik & Input-Typen
Formulare sind der Ort, an dem semantisches HTML am meisten zurückgibt. Der richtige Input-Typ liefert nicht nur Bedeutung, sondern gleich fertiges Verhalten: die passende Tastatur am Smartphone, eine erste Prüfung ohne Server, das richtige Autofill. Nichts davon musst du programmieren – du wählst es aus. Diese Seite betrachtet Formulare aus dem Semantik-Blick: welches Element welche Bedeutung trägt und welches Verhalten der Browser dafür geschenkt mitbringt. Die Bedienbarkeit im Detail – Labels, Fehlermeldungen, Validierung – vertieft der Komponenten-Bereich.
Die gute Nachricht vorweg: HTML kennt für nahezu jede Eingabe bereits ein passendes Element oder einen passenden Typ. Wer sie nutzt, baut Formulare, die schneller zu bedienen, robuster und zugänglicher sind – mit weniger Code.
Das <form>-Element: die semantische Klammer
<form> umschließt zusammengehörige Felder als eine logische Einheit. Das ist mehr als Kosmetik: Erst dadurch entstehen das Absenden per Enter, die native Prüfung vor dem Abschicken und der Kontext „hier wird etwas eingegeben“, den assistive Technologien brauchen. Ein Screenreader kennt eine search-Rolle für Suchformulare und behandelt Formularbereiche als eigene Region. Ein loses Sammelsurium aus <input>-Elementen ohne <form> verschenkt all das.
Beim Absenden schickt der Browser jedes Feld als name=Wert-Paar. Der name ist damit keine Nebensache, sondern der Schlüssel, unter dem der Server den Wert wiederfindet – ohne name wird ein Feld gar nicht erst übertragen.
<form action="/anmelden" method="post">
<label for="mail">E-Mail</label>
<input type="email" id="mail" name="mail" autocomplete="email" required />
<button type="submit">Anmelden</button>
</form>
method: GET oder POST – eine Bedeutungsfrage
Das method-Attribut ist eine semantische Aussage darüber, was das Absenden bewirkt:
method |
Bedeutung | Wann |
|---|---|---|
get (Standard) |
Abfrage ohne Nebenwirkung – die Werte hängen als ?a=1&b=2 an der URL |
Suche, Filter, Sortierung – Ergebnisse, die man teilen und bookmarken kann |
post |
Vorgang mit Wirkung – die Werte reisen im Anfrage-Körper, nicht in der URL | Anmeldung, Bestellung, Upload, alles Anlegen/Ändern/Löschen |
dialog |
schließt einen umgebenden <dialog> und meldet die Eingabe, ohne etwas zu senden |
Formulare innerhalb eines nativen Dialogs |
Die Faustregel folgt direkt aus der HTTP-Semantik: GET fragt ab, POST verändert. Eine Suche gehört per GET in die URL (wiederholbar, teilbar, ohne Seiteneffekt); ein Kauf oder Login gehört per POST in den Körper (nicht wiederholbar, nicht im Verlauf sichtbar). Wählst du falsch, funktioniert das Formular oft trotzdem – aber es „lügt“ über seine Wirkung, und Passwörter landen in der Adresszeile.
enctype, novalidate, target
Ergänzend steuern drei Attribute das Absende-Verhalten:
-
enctype(nur bei POST):application/x-www-form-urlencodedist der Standard. Für Datei-Uploads mit<input type="file">ist zwingendmultipart/form-datanötig – sonst kommt nur der Dateiname, nicht die Datei an. -
novalidateschaltet die native Prüfung für das ganze Formular ab;formnovalidatean einem einzelnen Button tut dasselbe nur für ihn (praktisch für „Entwurf speichern“). -
targetbestimmt, wo die Antwort erscheint (_self,_blank…) – bei modernen Anwendungen selten gebraucht, da JavaScript das Absenden oft übernimmt.
Das form-Attribut: Felder außerhalb des Formulars
Ein Steuerelement muss nicht innerhalb des <form> stehen. Mit dem form-Attribut, das auf die id des Formulars zeigt, gehört ein Feld logisch dazu, obwohl es im DOM woanders liegt:
<form id="suche" action="/suche" method="get"></form>
…
<input type="search" name="q" form="suche" />
<button type="submit" form="suche">Suchen</button>
Das rettet Layouts, in denen sich verschachteltes HTML nicht sauber umsetzen lässt – die Zusammengehörigkeit bleibt für Browser und assistive Technik trotzdem erhalten.
Die Bausteine: welches Element wofür
Bevor es um Input-Typen geht, lohnt der Überblick über die form-assoziierten Elemente. Jedes trägt eine eigene Bedeutung – der Griff zum passenden erspart den Nachbau:
| Element | Bedeutung |
|---|---|
<input> |
Einzeiliges Feld; sein type bestimmt Bedeutung und Verhalten |
<textarea> |
Mehrzeiliger, frei umbrechbarer Text |
<select> / <option> |
Auswahl aus einer festen Liste; <optgroup> gruppiert Optionen |
<button> |
Bedienelement zum Absenden oder für Aktionen |
<label> |
Verbindet Beschriftung und Feld – die Grundlage jeder Bedienbarkeit |
<fieldset> / <legend> |
Fasst zusammengehörige Felder unter einer gemeinsamen Überschrift |
<datalist> |
Vorschlagsliste zu einem Textfeld (Tippen bleibt möglich) |
<output> |
Ergebnis einer Berechnung, für Screenreader automatisch angesagt |
<progress> |
Fortschritt eines Vorgangs (0 … max) |
<meter> |
Skalarer Messwert in bekanntem Bereich (z. B. Füllstand) |
Input-Typen tragen Bedeutung
Der type eines <input> ist gelebte Semantik – er sagt, was erwartet wird, und löst passendes Verhalten aus: die richtige Bildschirmtastatur, eine native Formatprüfung, das passende Autofill. Die 22 Typen lassen sich in Gruppen ordnen.
Text-artige Eingaben
type |
Bedeutung & Effekt |
|---|---|
text |
Beliebiger einzeiliger Text – der Standard, ohne Sonderverhalten |
search |
Suchfeld – oft mit Lösch-Kreuz, „Suchen“-Taste, gespeicherten Eingaben |
email |
E-Mail – Tastatur mit @, native Formatprüfung; multiple erlaubt mehrere |
url |
Webadresse – URL-Tastatur, prüft auf gültiges Schema (https: …) |
tel |
Telefonnummer – Ziffern-Tastatur, aber keine Formatprüfung (Nummern sind zu vielfältig) |
password |
Verdeckte Eingabe – Zeichen werden maskiert |
Zwei Feinheiten sind wichtig: type="email" akzeptiert bewusst auch name@intranet (ohne Punkt), weil interne Adressen gültig sind. Und type="tel" prüft nichts – willst du ein Format erzwingen, kombinierst du es mit pattern (siehe unten).
<label for="mail">E-Mail</label>
<input type="email" id="mail" name="mail" autocomplete="email" />
Am Smartphone erscheint so die passende Tastatur, und der Browser prüft das Format – geschenkt, nur durch die richtige Typwahl.
Zahlen: number und range
-
numberliefert ein Feld mit Auf-/Ab-Pfeilen und akzeptiert nur Zahlen. Ideal für echte Mengen mit Ober- und Untergrenze (min,max,step). Vorsicht bei Werten, die zwar aus Ziffern bestehen, aber keine Rechengrößen sind – Postleitzahl, Konto- oder Kreditkartennummer.numberentfernt dort führende Nullen und lädt zum versehentlichen „Hochscrollen“ ein. Für solche Fälle isttype="text"mitinputmode="numeric"die bessere Wahl. -
rangeist ein Schieberegler für ungefähre Werte (Preisgrenze, Lautstärke). Da der gewählte Wert nicht sichtbar ist, koppelt man ihn typischerweise an ein<output>.
<label for="preis">Maximalpreis</label>
<input type="range" id="preis" name="preis" min="0" max="1000" step="50" value="500" />
<output for="preis">500</output>
Datum & Zeit
type |
Erfasst | Nativer Helfer |
|---|---|---|
date |
Datum (Jahr-Monat-Tag) | Kalender-Widget |
time |
Uhrzeit | Zeit-Auswahl |
datetime-local |
Datum und Uhrzeit (ohne Zeitzone) | Kalender + Zeit |
month |
Monat und Jahr | Monats-Auswahl |
week |
Kalenderwoche und Jahr | Wochen-Auswahl |
Der große Gewinn: Der übertragene Wert ist immer normiert (2026-07-18), egal wie die Nutzerin ihn in ihrer Landessprache eingibt. min, max und step grenzen den erlaubten Bereich ein. Wo ein eigener, aufwendiger Datepicker nötig ist, lohnt der Blick auf die barrierefreie Datums- & Zeitauswahl – oft reicht aber das native Feld.
Auswahl, Farbe, Datei
-
checkbox– einzelne Ja/Nein-Entscheidung oder Mehrfachauswahl. Mehrere Checkboxen mit gleichemnamebilden eine Gruppe. -
radio– Auswahl genau einer Option. Alle Radios mit demselbennamegehören zusammen; nur eines lässt sich wählen. -
color– öffnet den nativen Farbwähler und liefert einen sechsstelligen Hex-Wert (#ff0000). -
file– öffnet den Datei-Dialog;acceptschränkt die Typen ein (image/*),multipleerlaubt mehrere Dateien. Brauchtenctype="multipart/form-data". -
hidden– überträgt einen Wert, den die Nutzerin nicht sieht (z. B. eine Datensatz-ID).
Buttons: mit Bedeutung absenden
Ein Button ist nicht gleich ein Button – sein type bestimmt, was er tut:
type |
Aufgabe |
|---|---|
submit |
Formular absenden (Standard innerhalb eines <form>) |
button |
Reine JavaScript-Aktion, sendet nicht ab |
reset |
Setzt alle Felder zurück – aus UX-Sicht meist zu vermeiden (versehentliches Löschen) |
Bevorzuge das eigenständige <button>Text</button>: Es kann Text, Icons und Markup umschließen, die ein Screenreader vorliest. Die Input-Varianten (<input type="submit">) brauchen ihren Text im value, und ein <input type="image"> zwingend ein alt. Wofür ein <button> und wofür ein <a> das richtige Element ist, trennt Buttons vs. Links.
Randnotiz – ein falscher
typesendet unerwartet ab. Ein<button>ohnetypeinnerhalb eines Formulars gilt alssubmit. Der „Passwort anzeigen“-Button, der plötzlich das halb ausgefüllte Formular abschickt, ist fast immer ein vergessenestype="button".
Die richtige Tastatur: inputmode und enterkeyhint
Manchmal willst du eine bestimmte Bildschirmtastatur, ohne den ganzen Typ zu wechseln. Dafür gibt es inputmode – ein reiner Tastatur-Hinweis, ohne eigene Prüfung:
inputmode |
Tastatur |
|---|---|
text |
Standardtastatur (Voreinstellung) |
numeric |
nur Ziffern 0–9 (z. B. PIN, Kontonummer) |
decimal |
Ziffern mit Dezimaltrenner |
tel |
Telefon-Tastenfeld |
email |
mit @-Taste |
url |
mit /-Taste |
search |
Return-Taste als „Suchen“ |
none |
keine – für eigene Eingabeoberflächen |
Der Unterschied zum type: type prüft und trägt Bedeutung, inputmode beeinflusst nur die Tastatur. Wo ein passender Typ existiert (email, tel, url, number), nimm ihn. inputmode glänzt bei Sonderfällen – etwa einer Kontonummer, die man als type="text" inputmode="numeric" erfasst, um die Zifferntastatur zu bekommen, ohne die Tücken von type="number".
Verwandt ist enterkeyhint: Es beschriftet die Enter-Taste passend zur Aufgabe – enter, done, go, next, previous, search oder send. In einem mehrstufigen Formular sagt next der Nutzerin, dass es weitergeht statt abzusenden.
Eingaben einschränken: die Constraint-Attribute
HTML bringt eine erste Prüfschicht selbst mit – ganz ohne JavaScript. Diese Attribute beschreiben, was ein Feld annimmt:
| Attribut | Wirkung | Passt zu |
|---|---|---|
required |
Pflichtfeld – leer verhindert das Absenden | fast allen Typen |
pattern |
regulärer Ausdruck, den der Wert erfüllen muss | Text-Typen |
min / max |
erlaubter Zahlen- oder Datumsbereich | number, range, Datum/Zeit |
step |
erlaubte Schrittweite | number, range, Datum/Zeit |
minlength / maxlength |
Mindest-/Höchstlänge in Zeichen | Text-Typen |
multiple |
mehrere Werte erlaubt | email, file |
accept |
erlaubte Dateitypen | file |
readonly |
nicht änderbar, wird aber mitgesendet | Text-Typen |
disabled |
inaktiv und wird nicht mitgesendet | alle |
Der Browser prüft diese Vorgaben beim Absenden und zeigt eine native Meldung an. Über die Pseudoklassen :valid, :invalid und – besser für die UX – :user-invalid lässt sich der Zustand gestalten, ohne bei jedem Tastendruck rot aufzuleuchten:
/* Erst nach der Interaktion als fehlerhaft markieren */
input:user-invalid {
border-color: #c0392b;
}
Ein wichtiger Merksatz bleibt: Die native Prüfung ist Komfort, keine Sicherheit. Sie fängt Tippfehler früh ab, lässt sich aber umgehen. Eine belastbare, serverseitige Prüfung gehört immer dazu – die zugängliche Umsetzung der sichtbaren Fehlerbehandlung zeigt Validierung & Pflichtfelder.
autocomplete: Bedeutung maschinenlesbar machen
Das autocomplete-Attribut benennt die Bedeutung eines Feldes maschinenlesbar. Damit weiß der Browser, dass hier der Vorname, dort die Straße und daneben das aktuelle Passwort steht – und kann korrekt vorausfüllen. Das nimmt allen Nutzern Tipparbeit ab, hilft besonders Menschen mit motorischen oder kognitiven Einschränkungen und erfüllt zugleich das WCAG-Kriterium 1.3.5 Eingabezweck bestimmen.
<input type="text" id="vorname" name="vorname" autocomplete="given-name" />
Die Werte sind ein festes Vokabular, keine Freitexte. Häufig gebraucht:
| Bereich | Tokens |
|---|---|
| Name | name, given-name, family-name, honorific-prefix, nickname |
| Kontakt | email, tel, tel-national, impp |
| Adresse | street-address, address-line1/-line2, postal-code, address-level2 (Ort), country-name |
| Konto | username, current-password, new-password, one-time-code |
| Zahlung | cc-name, cc-number, cc-exp, cc-csc |
| Sonstiges | bday, organization, url |
Für zusammengesetzte Angaben lassen sich Tokens in fester Reihenfolge kombinieren: ein optionaler Abschnitt (section-*), dann shipping oder billing, dann ein Kontakttyp (home, work, mobile) und zuletzt das eigentliche Detail-Token. So unterscheidet ein Formular Liefer- von Rechnungsadresse:
<input autocomplete="shipping street-address" />
<input autocomplete="billing street-address" />
Zwei Sonderfälle sind Gold wert: autocomplete="new-password" sagt dem Passwort-Manager, hier ein neues starkes Passwort vorzuschlagen; autocomplete="one-time-code" erlaubt es dem Smartphone, den per SMS erhaltenen Code direkt anzubieten – ein spürbarer Gewinn für zugängliche Authentifizierung.
Und autocomplete="off"? Nur, wo es wirklich sein muss (Einmal-Codes, Captchas). Es pauschal übers ganze Formular zu legen, sabotiert das Autofill – und Passwortmanager ignorieren es bei Anmeldefeldern ohnehin oft, aus gutem Grund.
Randnotiz – Bedeutung spart Bedienarbeit. Jede dieser Angaben kostet kaum Aufwand, nimmt Nutzern aber Arbeit ab: die richtige Tastatur, ausgefüllte Felder, eine erste Prüfung ohne Server. Semantik im Formular ist damit unmittelbar spürbarer Komfort – und ein gutes Stück Barrierefreiheit gleich mit.
Auswahllisten: select, optgroup und datalist
Für eine feste Auswahl ist <select> das richtige Element – nativ per Tastatur bedienbar, mit Suche-beim-Tippen und einer plattformeigenen Darstellung. Lange Listen gliedert <optgroup> mit einer label-Überschrift:
<label for="land">Land</label>
<select id="land" name="land">
<optgroup label="Europa">
<option value="de">Deutschland</option>
<option value="at">Österreich</option>
</optgroup>
<optgroup label="Amerika">
<option value="us">USA</option>
</optgroup>
</select>
Soll die Nutzerin frei tippen oder aus Vorschlägen wählen können, ist <datalist> das semantische Werkzeug. Es hängt sich per list-Attribut an ein normales Textfeld und schränkt die Eingabe nicht ein:
<label for="stadt">Stadt</label>
<input type="text" id="stadt" name="stadt" list="staedte" />
<datalist id="staedte">
<option value="Berlin"></option>
<option value="Hamburg"></option>
<option value="München"></option>
</datalist>
Reicht die native Vorschlagsliste nicht (etwa für Autocomplete mit Nachladen), führt der Weg zur Combobox – aber erst, wenn <datalist> wirklich nicht genügt.
Zusammengehöriges gruppieren: fieldset und legend
Mehrere Felder, die zu einer Frage gehören – etwa eine Gruppe von Radio-Buttons – bekommen mit <fieldset> eine Klammer und mit <legend> eine gemeinsame Überschrift. Ein Screenreader stellt die legend jeder einzelnen Option voran, sodass „Standard, Optionsfeld“ zu „Versandart, Standard, Optionsfeld“ wird. Das ist reine Semantik – die Beziehung wird sichtbar und programmatisch. Details und Grenzen zeigt fieldset & legend.
Ergebnisse und Zustände: output, progress, meter
Auch die Ausgabe im Formular hat eigene Elemente – oft übersehen:
-
<output>hält das Ergebnis einer Berechnung (Zwischensumme, Reglerwert). Es ist von Haus aus eine Live-Region: Ändert sich sein Inhalt, sagt der Screenreader ihn an. -
<progress>zeigt den Fortschritt eines Vorgangs (valuevon0bismax); ohnevalueist er unbestimmt („läuft noch“). -
<meter>stellt einen Messwert in einem bekannten Bereich dar – Festplatten-Füllstand, Passwortstärke –, nicht aber Fortschritt. Mitlow,highundoptimumfärbt der Browser den Balken sogar sinnvoll ein.
<progress> und <meter> verwechseln viele: Fortschritt bewegt sich auf ein Ziel zu, ein Messwert beschreibt einen Ist-Zustand.
Warum native Elemente – und nicht <div>-Nachbau
Der rote Faden all dessen: Ein <div>, das mit JavaScript zum Eingabefeld umgebaut wird, sieht vielleicht gleich aus – bringt aber nichts von dem mit, was die nativen Elemente geschenkt liefern. Was beim Nachbau verloren geht:
- Tastaturbedienung und Fokus – nativ vorhanden, sonst mühsam nachzurüsten.
- Ansage für Screenreader (Name, Rolle, Wert – siehe 4.1.2).
- Autofill und die maschinenlesbare Bedeutung aus
autocomplete. - Die passende Bildschirmtastatur am Smartphone.
- Die native Prüfung über
required,pattern& Co. - Das Absenden selbst – ein
<div>ist kein Formularfeld und reist nicht mit.
Das ist die erste Regel von ARIA in Reinform: Nutze das native Element, statt seine Semantik von Hand nachzubauen. Wie schnell aus vermeintlich flexiblen <div>-Konstruktionen eine unwartbare „div-soup“ wird, zeigt der eigene Artikel dazu.
Live-Beispiel: ein durchsemantisiertes Formular
Jedes Feld unten trägt den passenden Typ, ein verknüpftes Label und – wo sinnvoll – ein autocomplete-Token. Probier es mit der Tastatur und, wenn möglich, am Smartphone:
Live-Beispiel: semantische Feldtypen
Kein einziges Feld braucht dafür JavaScript: passende Tastatur, Kalender, Zahlenpfeile und Autofill kommen allein aus der richtigen Typwahl.
Häufige Fehler
-
Alles als
type="text", obwohlemail,tel,dateodernumberpassen würden – und damit passende Tastatur, Prüfung und Autofill verschenkt. -
Felder ohne
<form>, wodurch Enter-Absenden, Kontext und native Prüfung fehlen. -
Fehlendes
name-Attribut, sodass ein Feld gar nicht erst übertragen wird. -
type="number"für Konto-, Karten- oder Postleitzahlen, die dadurch führende Nullen verlieren und sich versehentlich verstellen lassen (inputmode="numeric"ist besser). -
<div>mit Klick-Handler als Button statt<button type="submit">. -
<button>ohnetypeim Formular, der ungewollt absendet. -
autocompleteungenutzt oder pauschaloff, sodass Autofill raten muss oder gar nicht greift. - Placeholder als Ersatz fürs Label – der Hinweis verschwindet beim Tippen und ist kein Ersatz für ein echtes Label.
- Native Typen per JavaScript nachbauen, obwohl der native Typ gereicht hätte.
Häufige Fragen
Ersetzt der Input-Typ die Validierung?
Nein, er ergänzt sie. Die native Prüfung ist eine erste, komfortable Stufe – sie lässt sich aber umgehen. Eine vollständige, zugängliche Validierung und eine serverseitige Prüfung gehören zusätzlich dazu.
Warum nicht für alles type="text"?
Weil der spezifische Typ Bedeutung und Verhalten liefert – passende Bildschirmtastatur, Formatprüfung, Autofill, native Auswahlhelfer. text verschenkt das alles und schiebt die Arbeit auf dich und die Nutzerin ab.
Wann type="number" und wann inputmode="numeric"?
type="number" passt zu echten Rechengrößen mit Grenzen (Menge, Alter). Für Ziffernfolgen, die keine Zahlen im mathematischen Sinn sind – Konto-, Karten- oder Postleitzahl –, nimmst du besser type="text" mit inputmode="numeric": Zifferntastatur ja, aber ohne verlorene führende Nullen und ohne versehentliches Hoch-/Runterzählen.
Brauche ich für jedes Feld autocomplete?
Für persönliche Standarddaten (Name, E-Mail, Adresse, Telefon) ja – es hilft spürbar und erfüllt WCAG 1.3.5. Für freie, einmalige Eingaben ohne feste Bedeutung ist es nicht nötig.
Was ist der Unterschied zwischen inputmode und type?
type bestimmt Bedeutung und Verhalten (inklusive Prüfung und Datenformat); inputmode beeinflusst nur die angezeigte Bildschirmtastatur. Gibt es einen passenden type, nimm ihn; inputmode ist für Sonderfälle da.
Muss ein Button innerhalb des <form> stehen?
Nein. Mit dem form-Attribut, das auf die id des Formulars zeigt, gehört ein Button oder Feld logisch dazu, obwohl es im DOM außerhalb liegt.
Fazit
Formular-Semantik heißt: <form> als Klammer mit dem richtigen method, für jedes Feld der passende Input-Typ samt seiner Constraint-Attribute, die richtigen Bausteine (button, select, datalist, textarea, label), inputmode für Sonderfälle und autocomplete für Autofill und WCAG 1.3.5. Jede dieser Entscheidungen liefert Bedeutung und fertiges Verhalten – die beste Bedienbarkeit ist die, die du nicht selbst bauen musst. Wie diese semantische Basis zur voll zugänglichen Bedienung wird, zeigen Labels und Validierung.