Jetzt, in 2026, zeigte ein Code-Review einige Schwachstellen – und der Code wurde weiter überarbeitet.

Der Code-Review

Der Review fand fünf Punkte – von ernsthafter Schwachstelle bis zu kleinen Unschönheiten.

Das grösste Problem war ein Listener-Leak: Jeder Aufruf der setup()-Funktion hängte einen weiteren input-Listener an dasselbe Element. Wurde das Element mehrfach initialisiert, stapelten sich die Listener still und leise. Kein Fehler, kein Hinweis.

Dazu kam ein fehleranfälliger Ansatz für versteckte Felder: War die Textarea zum Zeitpunkt der Initialisierung nicht sichtbar, wartete der Code 500 Millisekunden und prüfte einmal – genau einmal –, ob sie jetzt sichtbar ist. War sie es nicht, passierte nichts mehr.

Ein weiterer Punkt: Wurde das Feld schmaler – auf einem Mobilgerät oder bei Rotation –, passte sich die Höhe nicht an. Der Code reagierte nur auf Texteingabe, nicht auf Breitenänderungen.

Kleiner, aber der Vollständigkeit halber: Für das data-init-height-Attribut hatte ich einen Check eingebaut, der den Wert 0 fälschlich als ungültig verwarf. Dazu zwei weitere kleinere Unschönheiten in meinem eigenen Code, die ich ebenfalls bereinigt habe.

Was ich behalten habe

Das Original stammt von Stefan Haack. Die Kernidee – die Mathematik dahinter – habe ich bewusst behalten. Warum etwas anfassen, das funktioniert?

Das Prinzip: Beim ersten Laden werden zwei Werte gemessen – die aktuelle Höhe des Feldes und seine scrollHeight. Diese beiden Werte dienen als Baseline. Bei jeder Texteingabe danach wird die neue Höhe als Differenz berechnet: Basishöhe plus die Veränderung im scrollHeight. Weil in Differenzen gerechnet wird, fallen Padding und Border heraus – das Ergebnis ist unabhängig vom box-sizing. Hätte ich stattdessen einfach height = scrollHeight gesetzt, würde das in vielen Fällen funktionieren, aber eben nicht immer.

Ein kleiner Trick, bei dem das Feld vor der Messung kurz auf display:block gesetzt wird, wurde ebenfalls behalten – damit der Browser einen korrekten Wert liefert. Und eine Korrektur von zwei Pixeln für Felder, die bereits vor der Messung überlaufen.

Ein vorbefülltes Feld schrumpft entsprechend nicht unter seine Anfangshöhe – das ist bewusst so und in der Praxis korrekt.

Die Verbesserungen

Die Verbesserungen folgen direkt aus dem Review.

Der erste Schritt war eine Prüfung beim Start: Wurde das Feld bereits initialisiert, passiert nichts mehr. Kein gestapelter Listener.

Das fehleranfällige Timing-Problem – der einmalige 500-Millisekunden-Timer – wurde durch einen ResizeObserver ersetzt. Der beobachtet das Feld und reagiert, sobald es sichtbar wird. Gleichzeitig löst er einen Reflow aus, wenn sich die Breite ändert – auf dem Mobilgerät, bei Rotation, bei einem responsiven Layout. Der ResizeObserver ist ab Browsern von etwa 2019 verfügbar – wo er fehlt, greift der alte Timer automatisch.

Dazu kam eine Konfiguration per data-Attribut: data-init-height und data-max-height. Letzteres hat einen Standard von 600 Pixeln – wichtig für Fälle, in denen man den JavaScript-Aufruf nicht direkt kontrolliert. Warum das relevant ist, kommt im nächsten Abschnitt.

Die fehlerhaften Guards und die übrigen Kleinigkeiten aus dem Review wurden ebenfalls bereinigt.

WordPress mit Contact Form 7

Contact Form 7 rendert sein Textarea-Feld mit der Klasse wpcf7-textarea. Den Selektor im Theme habe ich bewusst darauf ausgerichtet – neben textarea.auto-resize für alle anderen Felder, wo ich das Attribut setzen kann. Somit braucht es für das CF7-Feld kein extra data-max-height.

Code gratis herunterladen

Die überarbeitete Version ist auf GitHub verfügbar – mit Demo, Changelog und allem was dazugehört. Die MIT-Lizenz lässt dir alle Freiheiten: verwenden, anpassen, weitergeben. Den Credit an Stefan Haacks Original habe ich im Repo hinterlegt.

Der Grundgedanke des Resizings ist derselbe – der Code ist jetzt noch solider geworden und läuft zuverlässiger als zuvor.

Fragen, Feedback oder Fehler kannst du direkt als Issue auf GitHub melden.