HTML Formulare

Formulare sind das Bindeglied zwischen Nutzer*innen und Website - sie sammeln Informationen, schicken Daten ab und ermöglichen Interaktion. Code mit HTML5-Strukturelementen, der für Menschen, Suchmaschinen und Screenreader gleichermaßen verständlich ist.

Grundaufbau eines Formulars

Ein Formular beginnt immer mit dem <form>-Element. Darin befinden sich die Eingabefelder und Schaltflächen, die der Browser dann an den angegebenen Server oder eine andere Zieladresse sendet.

HTML
<form action="/formular-verarbeiten" method="post">
    <label for="name">Name:</label>
    <input type="text" id="name" name="name">
    
    <button type="submit">Absenden</button>
</form>

Form-Attribute

Die Attribute action und method steuern, wohin die Formulardaten geschickt werden und wie:

  • action = Zieladresse, z. B. eine Datei oder URL
  • method="get" = Daten in der URL (sichtbar)
  • method="post" = Daten im Request-Body (unsichtbar, sicherer)

Neben action und method gibt es weitere nützliche Attribute:

  • enctype - Für Datei-Uploads: "multipart/form-data"
  • novalidate - Schaltet Browser-Validierung aus
  • autocomplete="off" - Deaktiviert Auto-Vervollständigung
  • target="_blank" - Öffnet Ergebnis in neuem Tab
HTML
<!-- Formular mit Datei-Upload -->
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="dokument">
    <button type="submit">Hochladen</button>
</form>

Formular-Attribute erklärt - for, id, name & type

Wenn du dir Formular-Code anschaust, siehst du viele verschiedene Attribute, die auf den ersten Blick verwirrend wirken können:

HTML
<label for="name">Name:</label>
<input type="text" id="name" name="name" class="form-input">

Hier sehen wir for, type, id, name und class - das sind alles HTML-Attribute (keine CSS-Klassen!), und jedes hat eine eigene, wichtige Funktion:

HTML-Attribute ≠ CSS-Klassen!

Die meisten Attribute in Formularen haben nichts mit Styling zu tun, sondern steuern das Verhalten und die Funktion der Felder.

Die wichtigsten Attribute und ihre Funktionen

Attribut Wo? Funktion Beispiel
for <label> Verbindet das Label mit einem Input-Feld (muss mit id übereinstimmen) <label for="email">
id <input> Eindeutige ID für das Element (wichtig für Labels und CSS/JS) <input id="email">
name <input> Der Name, unter dem die Daten ans Backend gesendet werden <input name="user_email">
type <input> Bestimmt die Art des Eingabefelds (Text, E-Mail, Passwort...) <input type="email">
class Überall CSS-Klasse(n) für Styling <input class="form-input">

Warum brauchen wir alle diese Attribute?

Beispiel ohne eindeutige Namen:

HTML
<!-- Schlecht: alles heißt gleich -->
<label for="name">Name:</label>
<input type="text" 
       id="name" 
       name="name">

Problem: Wenn du mehrere Formulare hast, gibt's Konflikte - IDs müssen auf der ganzen Seite eindeutig sein!

Besser mit eindeutigen Namen:

HTML
<!-- Gut: eindeutige Namen -->
<label for="contact-name">Name:</label>
<input type="text" 
       id="contact-name" 
       name="user_name">

Vorteil: id ist eindeutig, name ist sprechend für die Datenbank.

Praktisches Beispiel: Alle Attribute im Einsatz

HTML
<form action="/register" method="post">
    <!-- Label verbindet sich mit Input über for/id -->
    <label for="register-email">E-Mail-Adresse</label>
    
    <input 
        type="email"           <!-- Art des Felds: E-Mail mit Validierung -->
        id="register-email"    <!-- Eindeutige ID für Label und CSS/JS -->
        name="user_email"      <!-- Name für Backend/Datenbank -->
        class="form-input"     <!-- CSS-Klasse für Styling -->
        placeholder="deine@email.de"  <!-- Hinweistext -->
        required>              <!-- Pflichtfeld -->
</form>

Was passiert hier?

  • type="email" → Browser validiert, ob eine E-Mail eingegeben wurde
  • id="register-email" → Verbindet sich mit <label for="register-email">
  • name="user_email" → Wenn du das Formular abschickst, kommt am Server an: user_email=deine@email.de
  • class="form-input" → Nur für CSS-Styling
Namenskonventionen
  • id → sprechend und eindeutig: contact-form-email, newsletter-signup-name
  • name → Backend-freundlich: user_email, customer_name (oft mit Unterstrichen)
  • class → wiederverwendbar: form-input, btn-primary

Eingabefelder (Text-basiert)

Das wichtigste Formular-Element ist <input>. Je nach type ändert sich das Verhalten und die Darstellung. Hier sind die textbasierten Typen:

Typ Beschreibung Beispiel
text Einzeiliges Texteingabefeld <input type="text">
email Validiert E-Mail-Format <input type="email">
password Versteckt eingegebenen Text <input type="password">
tel Telefonnummer (zeigt Zifferntastatur auf Mobilgeräten) <input type="tel">
url Validiert URL-Format <input type="url">
search Suchfeld (oft mit Lösch-Button) <input type="search">

Eingabefelder (Zahlen & Datum)

Diese Typen bieten spezielle UI-Elemente für Zahlen und Zeitangaben:

Typ Beschreibung Beispiel
number Nur Zahlen, mit Spinner-Buttons <input type="number" min="0" max="100">
range Schieberegler <input type="range" min="0" max="100">
date Datumsauswahl <input type="date">
time Zeitauswahl <input type="time">
datetime-local Datum und Uhrzeit kombiniert <input type="datetime-local">
month Monat und Jahr <input type="month">
week Kalenderwoche <input type="week">

Eingabefelder (Auswahl & Sonstige)

Diese Typen dienen zur Auswahl oder haben spezielle Funktionen:

Typ Beschreibung Beispiel
checkbox Ankreuzfeld (mehrere wählbar) <input type="checkbox">

radio Auswahl (nur eine Option) <input type="radio" name="gruppe">

color Farbauswahl-Dialog <input type="color">
file Datei-Upload <input type="file">
hidden Unsichtbares Feld (für technische Daten) <input type="hidden" name="token" value="abc123">
(nicht sichtbar)

Wichtige Input-Attribute

Diese Attribute erweitern die Funktionalität von Eingabefeldern:

Attribut Beschreibung
placeholder Grauer Hinweistext, verschwindet bei Eingabe
value Vorbelegter Wert im Feld
name Name für die Datenübertragung (wichtig für Backend!)
id Eindeutige ID (für Labels und CSS)
required Pflichtfeld
disabled Feld ist deaktiviert (nicht bearbeitbar, wird nicht gesendet)
readonly Feld ist schreibgeschützt (wird aber gesendet)
autofocus Setzt den Cursor automatisch in dieses Feld
autocomplete Steuert Browser-Autovervollständigung (on/off)
HTML
<!-- Beispiel mit verschiedenen Attributen -->
<input type="email" 
       id="email" 
       name="email" 
       placeholder="[email protected]"
       required
       autofocus
       autocomplete="email">

<!-- Schreibgeschütztes Feld mit Wert -->
<input type="text" 
       value="Dieser Wert ist fest" 
       readonly>

<!-- Deaktiviertes Feld -->
<input type="text" 
       value="Nicht verfügbar" 
       disabled>

Demo Browser-Default:





Demo mit CSS gestyled:

CSS anzeigen
CSS
/* Demo Container */
.demo-styled {
    padding: 1.5rem;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    margin: 1rem 0;
}

/* Labels */
.demo-styled label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--text-primary);
    font-weight: 500;
}

/* Input-Felder */
.demo-styled input[type="text"],
.demo-styled input[type="email"],
.demo-styled input[type="password"] {
    width: 100%;
    padding: 0.75rem 1rem;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 1rem;
    margin-bottom: 1rem;
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
}

/* Focus-Status */
.demo-styled input:focus {
    outline: none;
    border-color: var(--accent-blue-hover);
}

/* Placeholder */
.demo-styled input::placeholder {
    color: var(--text-muted);
}

/* Disabled Inputs ausgrauen */
.demo-styled input:disabled,
.demo-styled input[disabled] {
    color: var(--text-muted);
    background: var(--bg-primary);
    opacity: 0.6;
    cursor: not-allowed;
}

Für Auswahlmenüs und mehrzeilige Eingaben gibt es eigene Tags:

HTML
<!-- Dropdown/Select -->
<label for="land">Land:</label>
<select id="land" name="land">
    <option value="">Bitte wählen...</option>
    <option value="de">Deutschland</option>
    <option value="at">Österreich</option>
    <option value="ch">Schweiz</option>
</select>

<!-- Textarea für lange Texte -->
<label for="nachricht">Nachricht:</label>
<textarea id="nachricht" name="nachricht" rows="5" cols="40"></textarea>

Demo Browser-Default:





Demo mit CSS gestyled:

CSS anzeigen
CSS
/* Select & Textarea */
.demo-styled select,
.demo-styled textarea {
    width: 100%;
    padding: 0.75rem 1rem;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 1rem;
    margin-bottom: 1rem;
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
}

.demo-styled select:focus,
.demo-styled textarea:focus {
    outline: none;
    border-color: var(--accent-blue-hover);
}

.demo-styled textarea::placeholder {
    color: var(--text-muted);
}

Optgroup - Optionen gruppieren

Mit <optgroup> kannst du Dropdown-Optionen in Kategorien unterteilen:

HTML
<select name="fahrzeug">
    <optgroup label="Autos">
        <option value="vw">VW</option>
        <option value="bmw">BMW</option>
    </optgroup>
    <optgroup label="Motorräder">
        <option value="honda">Honda</option>
        <option value="yamaha">Yamaha</option>
    </optgroup>
</select>

Demo Browser-Default:

Demo mit CSS gestyled:

Das Styling von <optgroup> und <option> im Dropdown ist stark browserspezifisch begrenzt. Die meisten Browser rendern das Dropdown nativ und ignorieren viele CSS-Eigenschaften. Die größten Unterschiede sieht man am Select-Feld selbst (Padding, Border, Border-Radius, Focus-State).

CSS anzeigen
CSS
/* Select Dropdown */
.demo-styled select {
    width: 100%;
    padding: 0.75rem 1rem;
    background: var(--color-bg-darker, #0f0f1a);
    border: 1px solid var(--color-border, #3d3d5c);
    border-radius: 6px;
    color: var(--color-text, #e0e0e0);
    font-size: 1rem;
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
}

.demo-styled select:focus {
    outline: none;
    border-color: var(--color-accent, #6c9bd1);
    box-shadow: 0 0 0 3px rgba(108, 155, 209, 0.2);
}

/* Optgroup Labels (Gruppierungen) */
.demo-styled optgroup {
    font-weight: 600;
    color: var(--color-accent, #6c9bd1);
    font-style: normal;
}

/* Optionen innerhalb der Gruppen */
.demo-styled option {
    padding: 0.5rem;
    background: var(--color-bg-darker, #0f0f1a);
    color: var(--color-text, #e0e0e0);
}

Datalist - Auto-Vervollständigung

Das <datalist>-Element bietet Vorschläge während der Eingabe - die Nutzer*innen können aber auch eigene Werte eingeben:

HTML
<label for="browser">Browser:</label>
<input list="browsers" id="browser" name="browser" placeholder="Bitte auswählen...">

<datalist id="browsers">
    <option value="Chrome">
    <option value="Firefox">
    <option value="Safari">
    <option value="Edge">
    <option value="Opera">
</datalist>

Demo Browser-Default:


Demo mit CSS gestyled:

Bei <datalist> kann man leider nur das Input-Feld selbst stylen, nicht das aufklappende Dropdown (das rendert der Browser nativ).

CSS anzeigen
CSS
/* Input mit Datalist */
.demo-styled input[list] {
    width: 100%;
    padding: 0.75rem 1rem;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 1rem;
    font-family: inherit;
    transition: border-color 0.3s ease, box-shadow 0.3s ease;
}

.demo-styled input[list]:focus {
    outline: none;
    border-color: var(--accent-blue-light);
    box-shadow: 0 0 0 3px rgba(108, 155, 209, 0.2);
    background: var(--bg-secondary);
}

.demo-styled input[list]::placeholder {
    color: var(--text-muted);
}
Info

Der Unterschied zu <select>: Bei <datalist> sind die Optionen nur Vorschläge - Nutzer*innen können auch andere Werte eingeben.

Output, Progress & Meter

Diese HTML5-Elemente zeigen berechnete Werte oder Fortschritt an:

Element Beschreibung Beispiel
<output> Zeigt Berechnungsergebnis an 42
<progress> Fortschrittsbalken (Ladevorgang)
<meter> Messwert in bekanntem Bereich
HTML
<!-- Output für Berechnungen -->
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
    <input type="number" id="a" value="10"> +
    <input type="number" id="b" value="20"> =
    <output name="result" for="a b">30</output>
</form>

<!-- Progress: Fortschritt (0 bis max) -->
<label for="download">Download-Fortschritt:</label>
<progress id="download" value="70" max="100">70%</progress>

<!-- Meter: Messwert mit Schwellenwerten -->
<label for="disk">Speicherplatz:</label>
<meter id="disk" value="0.7" min="0" max="1" 
       low="0.3" high="0.8" optimum="0.5">70%</meter>
Progress vs. Meter

<progress> ist für Vorgänge (Laden, Upload), <meter> für statische Messungen (Speicher, Akku, Bewertungen). Meter hat zusätzlich low, high und optimum für farbliche Hervorhebung.

Fieldset & Legend - Felder gruppieren

Mit <fieldset> und <legend> kannst du zusammengehörige Formularfelder visuell und semantisch gruppieren. Das ist besonders wichtig für Barrierefreiheit:

HTML
<fieldset>
    <legend>Persönliche Daten</legend>
    
    <label for="vorname">Vorname:</label>
    <input type="text" id="vorname" name="vorname">
    
    <label for="nachname">Nachname:</label>
    <input type="text" id="nachname" name="nachname">
</fieldset>

<fieldset>
    <legend>Zahlungsmethode</legend>
    
    <label>
        <input type="radio" name="zahlung" value="karte">
        Kreditkarte
    </label>
    <label>
        <input type="radio" name="zahlung" value="paypal">
        PayPal
    </label>
    <label>
        <input type="radio" name="zahlung" value="rechnung">
        Rechnung
    </label>
</fieldset>

Demo Browser-Default:

Persönliche Daten




Zahlungsmethode

Demo mit CSS gestyled:

Persönliche Daten
Zahlungsmethode
CSS anzeigen
CSS
/* Fieldset & Legend */
.demo-styled fieldset {
    border: 1px solid var(--border-color);
    border-radius: 8px;
    padding: 1.5rem;
    margin-bottom: 1rem;
}

.demo-styled legend {
    color: var(--accent-blue);
    font-weight: 600;
    padding: 0 0.5rem;
}

/* Form Grid für nebeneinander liegende Felder */
.demo-styled .form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

@media (max-width: 600px) {
    .demo-styled .form-row {
        grid-template-columns: 1fr;
    }
}

/* Radio-Button Gruppe */
.demo-styled .radio-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.demo-styled .radio-group label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0;
    cursor: pointer;
}

.demo-styled input[type="radio"] {
    width: 1.25rem;
    height: 1.25rem;
    accent-color: var(--accent-blue);
}

Labels & Barrierefreiheit

Labels machen Formulare zugänglich - sie verbinden Beschriftungen mit Eingabefeldern. Der for-Wert muss dem id des Feldes entsprechen.

HTML
<!-- Explizites Label (empfohlen) -->
<label for="email">E-Mail-Adresse</label>
<input type="email" id="email" name="email" required>

<!-- Implizites Label (Input innerhalb des Labels) -->
<label>
    Newsletter abonnieren
    <input type="checkbox" name="newsletter">
</label>

ARIA-Attribute für bessere Zugänglichkeit

Zusätzliche Attribute helfen Screenreadern, den Inhalt korrekt wiederzugeben:

HTML
<!-- aria-label für Felder ohne sichtbares Label -->
<input type="search" aria-label="Website durchsuchen">

<!-- aria-describedby für zusätzliche Hinweise -->
<label for="passwort">Passwort</label>
<input type="password" id="passwort" aria-describedby="pw-hinweis">
<small id="pw-hinweis">Mindestens 8 Zeichen</small>

<!-- aria-required für Pflichtfelder -->
<input type="text" required aria-required="true">

<!-- aria-invalid für Validierungsfehler -->
<input type="email" aria-invalid="true" aria-errormessage="email-error">
<span id="email-error">Bitte gültige E-Mail eingeben</span>

Formularvalidierung

HTML5 bietet eingebaute Validierungsregeln - ohne JavaScript:

Attribut Beschreibung Beispiel
required Pflichtfeld <input required>
minlength / maxlength Min/Max Textlänge <input minlength="3" maxlength="20">
min / max Min/Max Zahlenwert <input type="number" min="1" max="100">
pattern Regex-Muster <input pattern="[A-Za-z]+">
step Erlaubte Schrittweite <input type="number" step="0.01">
HTML
<!-- Nur Buchstaben, mind. 2 Zeichen -->
<input type="text" 
       pattern="[A-Za-zÄÖÜäöüß\s]{2,}" 
       title="Nur Buchstaben, mindestens 2 Zeichen" 
       required>

<!-- Telefonnummer -->
<input type="tel" 
       pattern="[\+]?[0-9\s\-]{6,}"
       title="Gültige Telefonnummer eingeben">

<!-- Postleitzahl (5 Ziffern) -->
<input type="text" 
       pattern="[0-9]{5}" 
       title="5-stellige Postleitzahl">

Demo Browser-Default: Klicke auf "Prüfen".







Demo mit CSS gestyled: Klicke auf "Prüfen".

CSS anzeigen
CSS
/* Validierungsstatus visualisieren */
.demo-styled input:invalid:not(:placeholder-shown) {
    border-color: #ff6b6b;
}

.demo-styled input:valid:not(:placeholder-shown) {
    border-color: #51cf66;
}

/* Button Styling */
.demo-styled button {
    padding: 0.75rem 1.5rem;
    background: var(--color-accent, #6c9bd1);
    border: none;
    border-radius: 6px;
    color: #fff;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.3s ease, transform 0.2s ease;
}

.demo-styled button:hover {
    background: var(--color-accent-hover, #5a8ac0);
    transform: translateY(-1px);
}

Sicherheit bei Formularen

HTML-Validierung ist nur die erste Verteidigungslinie - sie kann clientseitig umgangen werden. Wichtige Sicherheitsaspekte:

Wichtig: Serverseitige Validierung

Niemals nur auf HTML-Validierung verlassen! Jeder kann die Browser-Validierung umgehen (DevTools, curl, etc.). Validiere immer auch serverseitig.

Best Practices

  • HTTPS verwenden: Formulardaten nur über verschlüsselte Verbindungen senden
  • CSRF-Schutz: Token gegen Cross-Site Request Forgery einsetzen
  • Eingaben sanitisieren: Serverseitig alle Eingaben bereinigen (SQL Injection, XSS)
  • Honeypot-Felder: Versteckte Felder gegen Spam-Bots
  • Rate Limiting: Anzahl der Formular-Einsendungen begrenzen
HTML
<!-- Honeypot-Feld gegen Spam-Bots -->
<form action="/submit" method="post">
    <!-- Dieses Feld wird per CSS versteckt -->
    <!-- Bots füllen es aus, Menschen nicht -->
    <input type="text" name="website" class="honeypot" 
           tabindex="-1" autocomplete="off">
    
    <!-- Echte Felder -->
    <input type="email" name="email" required>
    <button type="submit">Absenden</button>
</form>

<style>
.honeypot {
    position: absolute;
    left: -9999px;
    opacity: 0;
}
</style>

Die eigentliche Sicherheitslogik passiert im Backend - mehr dazu im PHP Security Tutorial.

Buttons

Buttons können Aktionen auslösen - der type bestimmt das Verhalten:

Typ Beschreibung
submit Sendet das Formular ab (Standard)
reset Setzt alle Felder auf Anfangswerte zurück
button Keine Standard-Aktion (für JavaScript)
HTML
<button type="submit">Absenden</button>
<button type="reset">Zurücksetzen</button>
<button type="button" onclick="alert('Klick!')">Klick mich</button>

<!-- Button mit Icon -->
<button type="submit">
    <svg>...</svg> Speichern
</button>

<!-- Deaktivierter Button -->
<button type="submit" disabled>Nicht verfügbar</button>

Demo Browser-Default:

Demo mit CSS gestyled:

CSS anzeigen
CSS
/* Buttons */
.demo-styled button {
    padding: 0.75rem 1.5rem;
    background: var(--color-accent, #6c9bd1);
    border: none;
    border-radius: 6px;
    color: #fff;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.3s ease, transform 0.2s ease;
}

.demo-styled button:hover {
    background: var(--color-accent-hover, #5a8ac0);
    transform: translateY(-1px);
}

.demo-styled button:active {
    transform: translateY(0);
}

/* Reset-Button in anderer Farbe */
.demo-styled button[type="reset"] {
    background: var(--color-bg-light, #2a2a4e);
    margin-left: 0.5rem;
}

.demo-styled button[type="reset"]:hover {
    background: var(--color-bg-lighter, #3a3a5e);
}

/* Deaktivierte Buttons */
.demo-styled button:disabled,
.demo-styled button[disabled] {
    background: var(--bg-tertiary);
    color: var(--text-muted);
    opacity: 0.5;
    cursor: not-allowed;
}

/* Hover-Effekt bei disabled Buttons deaktivieren */
.demo-styled button:disabled:hover,
.demo-styled button[disabled]:hover {
    background: var(--heading-dark);
    transform: none;
    box-shadow: none;
}

Praxis-Tipp: Barrierefreie Formulare

  • Labels immer mit Eingabefeldern verbinden
  • Fehlermeldungen klar und verständlich ausgeben
  • Logische Tab-Reihenfolge sicherstellen
  • Fokus sichtbar gestalten (z. B. durch CSS)
  • ARIA-Attribute nur ergänzend einsetzen
  • Ausreichend Kontrast für Text und Rahmen
CSS
/* Gut sichtbarer Fokus */
input:focus,
select:focus,
textarea:focus,
button:focus {
    outline: 3px solid #6c9bd1;
    outline-offset: 2px;
}

/* Validierungsstatus visualisieren */
input:valid {
    border-color: #51cf66;
}

input:invalid {
    border-color: #ff6b6b;
}

/* Pflichtfeld-Indikator */
label.required::after {
    content: " *";
    color: #ff6b6b;
}

Praxisbeispiel: Kontaktformular

Hier ein vollständiges Kontaktformular mit Betreffzeile, wie es auf der DevPanicZone aussehen könnte. Das Formular ist barrierefrei, validiert und responsiv.

HTML
<form action="/kontakt-verarbeiten.php" method="post" class="dpz-contact-form">
    <h3>Kontakt aufnehmen</h3>
    
    <div class="form-group">
        <label for="contact-name">Name *</label>
        <input type="text" id="contact-name" name="name" 
               placeholder="Dein Name" required>
    </div>
    
    <div class="form-group">
        <label for="contact-email">E-Mail *</label>
        <input type="email" id="contact-email" name="email" 
               placeholder="[email protected]" required>
    </div>
    
    <div class="form-group">
        <label for="contact-subject">Betreff *</label>
        <select id="contact-subject" name="subject" required>
            <option value="">Bitte wählen...</option>
            <option value="feedback">Feedback zum Tutorial</option>
            <option value="fehler">Fehler melden</option>
            <option value="vorschlag">Themenvorschlag</option>
            <option value="sonstiges">Sonstiges</option>
        </select>
    </div>
    
    <div class="form-group">
        <label for="contact-message">Nachricht *</label>
        <textarea id="contact-message" name="message" 
                  placeholder="Deine Nachricht..." required></textarea>
    </div>
    
    <div class="form-actions">
        <button type="submit" class="btn-submit">Nachricht senden</button>
        <button type="reset" class="btn-reset">Zurücksetzen</button>
    </div>
    
    <p class="privacy-note">* Pflichtfelder. Deine Daten werden nicht gespeichert.</p>
</form>

Live-Demo

So würde das Kontaktformular auf der DevPanicZone aussehen:

Kontakt aufnehmen

* Pflichtfelder. Deine Daten werden nicht gespeichert.

CSS anzeigen
CSS
/* DevPanicZone Kontaktformular */
.dpz-contact-form {    
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 2rem;
}

.dpz-contact-form .form-group {
    margin-bottom: 1.25rem;
}

.dpz-contact-form label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--text-primary);
    font-weight: 500;
    font-size: 0.9rem;
}

.dpz-contact-form input,
.dpz-contact-form select,
.dpz-contact-form textarea {
    width: 100%;
    padding: 0.875rem 1rem;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    color: var(--text-primary);
    font-size: 1rem;
    font-family: inherit;
    transition: all 0.3s ease;
}

.dpz-contact-form input:focus,
.dpz-contact-form select:focus,
.dpz-contact-form textarea:focus {
    outline: none;
    border-color: var(--accent-blue-light);
    box-shadow: 0 0 0 3px rgba(108, 155, 209, 0.15);
    background: var(--bg-tertiary);
}

.dpz-contact-form textarea {
    min-height: 150px;
    resize: vertical;
}

.dpz-contact-form .form-actions {
    display: flex;
    gap: 1rem;
    margin-top: 1.5rem;
}

.dpz-contact-form .btn-submit {
    flex: 1;
    padding: 1rem 2rem;
    background: var(--accent-blue-light);
    border: none;
    border-radius: 8px;
    color: #fff;
    font-weight: 600;
    font-size: 1rem;
    cursor: pointer;
    transition: all 0.3s ease;
}

.dpz-contact-form .btn-submit:hover {
    background: var(--accent-blue-light);
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(108, 155, 209, 0.4);
}

.dpz-contact-form .btn-reset {
    padding: 1rem 1.5rem;
    background: transparent;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    color: var(--text-muted);
    font-weight: 500;
    cursor: pointer;
    transition: all 0.3s ease;
}

.dpz-contact-form .btn-reset:hover {
    border-color: var(--border-color);
    color: var(--text-primary);
}

.dpz-contact-form .privacy-note {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-top: 1rem;
    text-align: center;
}

Alternative: 2-Spalten-Layout

Für breitere Layouts kannst du das Formular in zwei Spalten aufteilen - links die kurzen Felder, rechts die Nachricht:

HTML
<form action="/kontakt-verarbeiten.php" method="post" class="dpz-contact-form-wide">
    <h3>Kontakt aufnehmen</h3>
    
    <div class="form-columns">
        <!-- Linke Spalte -->
        <div class="form-column-left">
            <div class="form-group">
                <label for="contact-name">Name *</label>
                <input type="text" id="contact-name" name="name" 
                       placeholder="Dein Name" required>
            </div>
            
            <div class="form-group">
                <label for="contact-email">E-Mail *</label>
                <input type="email" id="contact-email" name="email" 
                       placeholder="[email protected]" required>
            </div>
            
            <div class="form-group">
                <label for="contact-subject">Betreff *</label>
                <select id="contact-subject" name="subject" required>
                    <option value="">Bitte wählen...</option>
                    <option value="feedback">Feedback zum Tutorial</option>
                    <option value="fehler">Fehler melden</option>
                    <option value="vorschlag">Themenvorschlag</option>
                    <option value="sonstiges">Sonstiges</option>
                </select>
            </div>
        </div>
        
        <!-- Rechte Spalte -->
        <div class="form-column-right">
            <div class="form-group">
                <label for="contact-message">Nachricht *</label>
                <textarea id="contact-message" name="message" 
                          placeholder="Deine Nachricht..." required></textarea>
            </div>
            
            <div class="form-actions">
                <button type="submit" class="btn-submit">Senden</button>
                <button type="reset" class="btn-reset">Zurücksetzen</button>
            </div>
        </div>
    </div>
    
    <p class="privacy-note">* Pflichtfelder</p>
</form>

Kontakt aufnehmen

* Pflichtfelder

CSS anzeigen
CSS
/* 2-Spalten Kontaktformular */
.dpz-contact-form-wide {
    width: 100%;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: 12px;
    padding: 2rem;
}

.dpz-contact-form-wide h3 {
    margin-top: 0;
    margin-bottom: 1.5rem;
    color: var(--accent-blue-light);
    font-size: 1.5rem;
}

.dpz-contact-form-wide .form-columns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2rem;
}

@media (max-width: 768px) {
    .dpz-contact-form-wide .form-columns {
        grid-template-columns: 1fr;
        gap: 0;
    }
}

.dpz-contact-form-wide .form-column-left,
.dpz-contact-form-wide .form-column-right {
    display: flex;
    flex-direction: column;
}

.dpz-contact-form-wide .form-group {
    margin-bottom: 1.25rem;
}

.dpz-contact-form-wide label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--text-primary);
    font-weight: 500;
    font-size: 0.9rem;
}

.dpz-contact-form-wide input,
.dpz-contact-form-wide select,
.dpz-contact-form-wide textarea {
    width: 100%;
    padding: 0.875rem 1rem;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 8px;
    color: var(--text-primary);
    font-size: 1rem;
    font-family: inherit;
    transition: all 0.3s ease;
}

.dpz-contact-form-wide input:focus,
.dpz-contact-form-wide select:focus,
.dpz-contact-form-wide textarea:focus {
    outline: none;
    border-color: var(--accent-blue-hover);
    box-shadow: 0 0 0 3px rgba(108, 155, 209, 0.15);
    background: var(--bg-primary);
}

.dpz-contact-form-wide .form-column-right {
    display: flex;
    flex-direction: column;
}

.dpz-contact-form-wide .form-column-right .form-group {
    flex: 1;
    display: flex;
    flex-direction: column;
}

.dpz-contact-form-wide .form-column-right textarea {
    flex: 1;
    min-height: 120px;
    resize: vertical;
}

.dpz-contact-form-wide .form-actions {
    display: flex;
    gap: 1rem;
    margin-top: 1rem;
}

.dpz-contact-form-wide .btn-submit {
    flex: 1;
    padding: 1rem 2rem;
    background: var(--accent-blue-light);
    border: none;
    border-radius: 8px;
    color: #fff;
    font-weight: 600;
    font-size: 1rem;
    cursor: pointer;
    transition: all 0.3s ease;
}

.dpz-contact-form-wide .btn-submit:hover {
    background: var(--color-accent-hover, #5a8ac0);
    transform: translateY(-2px);
    /* box-shadow: 0 4px 12px rgba(108, 155, 209, 0.4); */
}

.dpz-contact-form-wide .btn-reset {
    padding: 1rem 1.5rem;
    background: transparent;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    color: var(--text-muted);
    font-weight: 500;
    cursor: pointer;
    transition: all 0.3s ease;
}

.dpz-contact-form-wide .btn-reset:hover {
    border-color: var(--border-color);
    color: var(--text-primary);
}

.dpz-contact-form-wide .privacy-note {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-top: 1rem;
    text-align: center;
    grid-column: 1 / -1;
}
Demo Info

Diese Formulare sind nur Demos - um sie funktionsfähig zu machen, brauchst du ein Backend (z. B. PHP), das die Daten verarbeitet und die E-Mail versendet. Das behandeln wir im PHP-Tutorial!

Mehr aus HTML

Tutorials werden geladen...