Zum Inhalt springen
NativeCSS
Handbuch-Inhalt

Formulare

Native Elemente werden fertig gestylt (helpers/forms.css), keine JS-Nachbauten. Lebendes Beispiel: demo/forms.html.

Basis-Felder

KlasseZweck
.ncss-fieldLabel+Input+Hint als vertikale Gruppe
.ncss-label / --requiredFeld-Label, --required ergänzt ein rotes *
.ncss-input / .ncss-select / .ncss-textareaEinheitlicher Look, inkl. :user-invalid-Fehlerzustand
.ncss-field-hint / -errorHilfetext / Fehlertext unter einem Feld

Weitere Feldtypen (cross-browser gestylt)

TypBesonderheit
type="file"Größter Cross-Browser-Unterschied aller Feldtypen - ::file-selector-button (+ ::-webkit-file-upload-button für ältere Safari) bringt den Browser-Button auf .ncss-btn--secondary-Optik
type="color"Swatch-Fläche per ::-webkit-color-swatch(-wrapper)/::-moz-color-swatch an ncss-Radius angeglichen, feste Höhe passend zu den anderen Feldern
type="date/time/datetime-local/month/week"Kalender-/Uhr-Icon folgt automatisch dem Theme (color-scheme), keine eigene Anpassung nötig
type="search"appearance: none nötig, sonst rundet Safari das Feld eigenständig komplett ab
type="number"Native Spinner-Pfeile bewusst NICHT entfernt - echte Funktionalität, kein Grund sie zu kappen
<input list> + <datalist>Nativer Combobox - editierbares Textfeld MIT Auswahlliste (anders als <select>, das nur Auswahl ohne freie Eingabe erlaubt). .ncss-input greift ohne Sonderregel (generisch auf jedes <input>)
<input class="ncss-input" list="staedte" placeholder="Wählen oder eingeben…">
<datalist id="staedte">
  <option value="Berlin"></option>
  <option value="Hamburg"></option>
</datalist>

Gestylte Dropdowns (opt-in)

Die native Vorschlagsliste eines <datalist> UND das Options-Popup eines <select> sind in keinem Browser per CSS stylebar (Stand 2026, geprüft) - für <select> gibt es mit appearance: base-select mittlerweile einen CSS-Weg, den ncss aktuell nur in Chrome/Edge 135+ aktiviert (siehe Komponenten-Referenz für die Begründung, warum Safari bewusst ausgenommen ist), für <datalist> gibt es gar keinen.

js/combobox.js (opt-in) ersetzt in beiden Fällen die native Popup-Optik durch eine echte, gestylte Dropdown-Liste - Original-Markup unverändert (<input list>/<datalist> bzw. <select>/<option>), volle native Funktion bleibt ohne JS bestehen (progressive enhancement, kein Funktionsverlust). Bei <select> greift es genau dort, wo ncss appearance: base-select NICHT aktiviert (Firefox UND aktuell auch Safari) - wo die native Technik bereits ein gestyltes Popup liefert (Chrome/Edge), tut das Script nichts.

<script src="js/combobox.js" defer></script>

<button><selectedcontent> als erstes Kind IMMER angeben, auch bei ganz normalem Text-Select - laut Spezifikation optional (der Browser erzeugt sonst selbst einen passenden Default-Button), macht das Verhalten aber über alle Browser hinweg konsistent und vorhersehbar.

<select class="ncss-select">
  <button type="button">
    <selectedcontent></selectedcontent>
  </button>
  <option>Option A</option>
  <option>Option B</option>
</select>

Reicher <option>-Inhalt (nativ nur mit appearance: base-select, sonst per js/combobox.js nachgebildet): <option> darf seit der "Customizable Select"-Erweiterung beliebige Kind-Elemente enthalten (Icon+Label statt nur Text), derselbe <button><selectedcontent> steuert dann zusätzlich die Anzeige im geschlossenen Zustand. "The Golden Rule of Customizable Select": Text bleibt Pflicht (sichtbar oder per .ncss-visually-hidden), Icons sind eine Ergänzung, nie ein Ersatz.

<select class="ncss-select">
  <button type="button">
    <selectedcontent></selectedcontent>
  </button>
  <option value="apfel">
    <span aria-hidden="true">🍎</span>
    <span>Apfel</span>
  </option>
</select>

js/combobox.js repliziert denselben reichen Inhalt für den JS-Fallback-Pfad (Firefox und aktuell auch Safari) - <option>-Kind-Elemente werden 1:1 in die custom Dropdown-Liste geklont statt nur der zusammengequetschte Text. Optisch identisches Ergebnis, per echtem Test in Chromium (nativ) sowie WebKit und Firefox (beide JS-Fallback) bestätigt.

Live-Suche (opt-in)

components/livesearch.css + js/livesearch.js zeigen schon während der Eingabe Treffer an - gruppiert (z.B. „Seiten“, „Personen“), mit markiertem Suchbegriff. Anders als js/combobox.js, das eine vorhandene <datalist> filtert, kommen die Treffer hier per fetch() vom Server. Muster: WAI-ARIA Combobox mit Listbox - der Fokus bleibt im Eingabefeld, aria-activedescendant zeigt auf die gewählte Option, eine Statusmeldung nennt die Trefferzahl. Ohne JavaScript bleibt es ein ganz normales Suchformular (Absenden führt zur Ergebnisseite).

<form class="ncss-livesearch" action="/suche/" role="search" data-ncss-livesearch="/api/suche">
  <label class="ncss-visually-hidden" for="q">Suche</label>
  <input id="q" class="ncss-input" type="search" name="q">
  <div class="ncss-livesearch-results" hidden></div>
</form>
<script src="js/livesearch.js" defer></script>

Antwort-Format des Endpoints (GET /api/suche?q=…, bereits gefiltert):

{
  "groups": [
    { "label": "Seiten", "items": [ { "title": "Kontakt", "url": "/kontakt/", "text": "Anfahrt und Öffnungszeiten" } ] }
  ],
  "all": "/suche/?q=..."
}
data-ncss-livesearchEndpoint (Pflicht)
data-paramName des Suchparameters, Default q
data-min / data-delayMindestlänge (Default 2) und Wartezeit nach dem letzten Tastendruck (Default 180 ms); ältere Anfragen werden per AbortController abgebrochen, Antworten pro Suchbegriff zwischengespeichert
data-mode="client"Endpoint ist eine STATISCHE JSON-Datei im selben Format (ungefiltert): einmal laden, im Browser filtern - für kleine Datenmengen ohne Server-Logik
data-text-empty/-all/-statusTexte überschreiben (Platzhalter {q}, {n}); Default Deutsch/Englisch nach <html lang>

Kombinierbar mit .ncss-search (wachsendes Suchfeld) und .ncss-input-group. Innerhalb eines <dialog> schließt Esc zuerst nur die Trefferliste, nicht den Dialog. Danach gilt wieder das Browser-Verhalten: ein type="search"-Feld leert beim nächsten Esc zuerst seinen Inhalt, erst das folgende Esc schließt den Dialog. Live: Demo.

Checkbox, Radio & Switch

.ncss-choiceCheckbox/Radio-Zeile - native Elemente, nur accent-color + Ausrichtung
.ncss-switchToggle-Switch aus <input type="checkbox">, per appearance:none neu gezeichnet, kein JS. role="switch" im Markup ergänzen
.ncss-rangeVereinheitlichtes <input type="range">, Track/Thumb angeglichen

Gruppierung & Rückmeldung

fieldset / legendOhne eigene Klasse zu Ende gestylt (wie <blockquote>) - ersetzt den nativen 3D-Rahmen
progress / meteraccent-color für die Grundfarbe. meter behält bewusst seine eigene Grün/Gelb/Rot-Bewertungslogik statt der Markenfarbe
outputHervorgehobene Darstellung für ein berechnetes Ergebnis

Input-Group

components/input-group.css - mehrere Formular-Steuerelemente visuell zu EINER Einheit verschmolzen (geteilte Rahmenlinie statt Lücke, nur die äußeren Ecken rund). Deckt zwei Fälle ab: Feld + Button (Suchleiste) und mehrere Felder nebeneinander (z.B. Vorname/Nachname). Bewusst NICHT "Form-Group" genannt - leicht zu verwechseln mit der bereits bestehenden <fieldset>/<legend>-Gruppierung (Semantik statt reiner Optik).

<label class="ncss-visually-hidden" for="search">Suchbegriff</label>
<div class="ncss-input-group">
  <input class="ncss-input" type="search" id="search" placeholder="Suchbegriff…">
  <button type="submit" class="ncss-btn ncss-btn--primary">Suchen</button>
</div>

Barrierefreiheit: placeholder ist KEIN Ersatz für ein Label - verschwindet bei Eingabe, wird nicht von jeder Screenreader-Software als Feldname angekündigt. Jedes Feld braucht ein echtes <label>, bei Bedarf per .ncss-visually-hidden versteckt - als Geschwister-Element VOR der .ncss-input-group, nicht als Kind hinein (sonst zählt es fälschlich als :first-child und die Eckenrundung landet auf dem unsichtbaren Label). Bei mehreren direkt verschmolzenen Feldern ohne Platz für ein Sibling-Label je Feld (z.B. Vorname/Nachname) ist aria-label direkt am <input> die richtige Technik, ohne die Kind-Struktur der Gruppe zu verändern:

<div class="ncss-input-group">
  <input class="ncss-input" aria-label="Vorname" placeholder="Vorname">
  <input class="ncss-input" aria-label="Nachname" placeholder="Nachname">
</div>

Deckt aktuell .ncss-input/-textarea/.ncss-btn als direkte Kinder ab - .ncss-select-wrapper (noch) nicht (der sichtbare Rahmen sitzt am inneren <select>, nicht am Wrapper selbst).

Buttons

.ncss-btn + --primary/--secondary/--danger. Jede Variante hat eine ECHTE :active-Rückmeldung (nicht nur :hover) - siehe Touch & mobile Viewports für die Begründung.

<button class="ncss-btn ncss-btn--primary">Absenden</button>