Autogrow textarea
Preview Available in release assets
Optionally grow a native textarea with its content while retaining a useful, resizable no-JavaScript control.
Autogrow textarea primary example
<div class="thin-field">
<label for="bio">Biography</label>
<textarea class="thin-textarea" id="bio" name="bio" data-enhance="autogrow" rows="3">
</textarea>
</div>Show code
<div class="thin-field">
<label for="bio">Biography</label>
<textarea class="thin-textarea" id="bio" name="bio" data-enhance="autogrow" rows="3">
</textarea>
</div>Variant gallery
Each authored example uses the production assets and includes copyable markup.
Authored rows with explicit enhancement
The three-row textarea is already usable. This example explicitly calls enhanceAutogrowTextareas(); type several lines to see it grow.
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-rows">Biography</label>
<textarea class="thin-textarea" id="bio-rows" name="bio" rows="3" data-enhance="autogrow">
</textarea>
</div>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
enhanceAutogrowTextareas(document);
</script>Show code
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-rows">Biography</label>
<textarea class="thin-textarea" id="bio-rows" name="bio" rows="3" data-enhance="autogrow">
</textarea>
</div>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
enhanceAutogrowTextareas(document);
</script>Theme-scaled maximum height
An authored max-block-size derived from the existing control-density token caps growth. Additional text scrolls inside the native editor; no private theme property is changed.
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-capped">Biography</label>
<textarea class="thin-textarea" id="bio-capped" name="bio" rows="3" data-enhance="autogrow" style="max-block-size: calc(var(--thin-density-control) * 4)">A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
</textarea>
</div>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
enhanceAutogrowTextareas(document);
</script>Show code
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-capped">Biography</label>
<textarea class="thin-textarea" id="bio-capped" name="bio" rows="3" data-enhance="autogrow" style="max-block-size: calc(var(--thin-density-control) * 4)">A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
A line of biography.
</textarea>
</div>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
enhanceAutogrowTextareas(document);
</script>Anatomy
- Native textarea
- data-autogrow opt-in
- Optional enhancement bundle
Variants and sizes
- Authored rows — shown above
- Theme-defined maximum block size — shown above
States and difficult content
Rendered fixtures exercise authored content and constrained layouts with the same production assets.
Unenhanced native textarea
No initialization script is included in this fixture. The opt-in marker alone changes no behavior; native scrolling and manual vertical resize remain available.
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-native">Biography</label>
<textarea class="thin-textarea" id="bio-native" name="bio" rows="3" data-enhance="autogrow">
</textarea>
</div>Show code
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-native">Biography</label>
<textarea class="thin-textarea" id="bio-native" name="bio" rows="3" data-enhance="autogrow">
</textarea>
</div>Enhanced editor with native reset
Add several lines, then reset the form. The optional behavior remeasures after the native value resets and retains the theme-scaled height limit.
<form style="display: grid; gap: 1rem">
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-reset">Biography</label>
<textarea class="thin-textarea" id="bio-reset" name="bio" rows="3" data-enhance="autogrow" style="max-block-size: calc(var(--thin-density-control) * 4)">Initial biography.</textarea>
</div>
<thin-button>
<button type="reset">Reset biography</button>
</thin-button>
</form>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
enhanceAutogrowTextareas(document);
</script>Show code
<form style="display: grid; gap: 1rem">
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-reset">Biography</label>
<textarea class="thin-textarea" id="bio-reset" name="bio" rows="3" data-enhance="autogrow" style="max-block-size: calc(var(--thin-density-control) * 4)">Initial biography.</textarea>
</div>
<thin-button>
<button type="reset">Reset biography</button>
</thin-button>
</form>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
enhanceAutogrowTextareas(document);
</script>Application-managed reconnection
Reconnect editor removes and reinserts its field after disconnecting the behavior, reconnects it once, and returns focus. This is explicit application lifecycle code, not automatic morph detection.
<form style="display: grid; gap: 1rem">
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-reconnect">Biography</label>
<textarea class="thin-textarea" id="bio-reconnect" name="bio" rows="3" data-enhance="autogrow">
</textarea>
</div>
<thin-button>
<button type="button" id="reconnect-bio">Reconnect editor</button>
</thin-button>
</form>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
const behavior = enhanceAutogrowTextareas(document);
document.querySelector("#reconnect-bio").addEventListener("click", () => {
const field = document.querySelector("[data-autogrow-field]");
const parent = field.parentNode;
const next = field.nextSibling;
behavior.disconnect();
field.remove();
parent.insertBefore(field, next);
behavior.connect(document);
field.querySelector("textarea").focus();
});
</script>Show code
<form style="display: grid; gap: 1rem">
<div class="thin-field" data-autogrow-field style="overflow-wrap: anywhere">
<label for="bio-reconnect">Biography</label>
<textarea class="thin-textarea" id="bio-reconnect" name="bio" rows="3" data-enhance="autogrow">
</textarea>
</div>
<thin-button>
<button type="button" id="reconnect-bio">Reconnect editor</button>
</thin-button>
</form>
<script type="module">
import { enhanceAutogrowTextareas } from "/behaviors.js";
const behavior = enhanceAutogrowTextareas(document);
document.querySelector("#reconnect-bio").addEventListener("click", () => {
const field = document.querySelector("[data-autogrow-field]");
const parent = field.parentNode;
const next = field.nextSibling;
behavior.disconnect();
field.remove();
parent.insertBefore(field, next);
behavior.connect(document);
field.querySelector("textarea").focus();
});
</script>- Unenhanced — shown above
- Enhanced — shown above
- Content constrained by maximum height — shown above
- Reset — shown above
- Reconnected — shown above
Interaction and keyboard behavior
The enhancement responds to input and form reset. Once the authored maximum is reached, the textarea scrolls normally.
Accessibility
The behavior does not alter the control role, name, focus, value, validation, or keyboard behavior.
- Contract
NATIVE- Basis
- Native <textarea> with bounded enhancement; no APG widget
- Evidence
tests/unit/behaviors/autogrow.test.ts
API
Add data-enhance=autogrow to <thin-textarea><textarea …></thin-textarea>, then call enhanceAutogrowTextareas(). Disconnect before replacing its root and reconnect or refresh afterward.
Behavior tier: dependency-free
Structured host, property, and example tables are not authored for this item yet. Use the summary above and the primary example.
Fallback
The authored textarea remains resizable, validated, scrollable, and submitted without the enhancement.
Assets and dependencies
/components.css/behaviors.js
Dependencies: None
Source: packages/ui/src/items/autogrow/style.ts
Composition
Derived from the examples and style specs, not authored.