Textarea

A multi-line text field that grows with its content.

Basic

Add .textarea to any <textarea>. The fixed-height contract from .input drops, so rows and content drive the height. The resize handle is vertical only, so the width tracks the parent.

<div class="w-100" style="max-width: 24rem;">
  <label for="basicTextarea" class="form-label">Notes</label>
  <textarea class="textarea" id="basicTextarea" rows="3" placeholder="Anything else we should know?"></textarea>
</div>

Sizes

Three sizes match the input scale so a textarea sits beside an input in the same row. Add .textarea--sm or .textarea--lg.

<div class="demo-stack w-100" style="max-width: 24rem;">
  <textarea class="textarea textarea--sm" rows="2" placeholder="Small"></textarea>
  <textarea class="textarea" rows="2" placeholder="Default"></textarea>
  <textarea class="textarea textarea--lg" rows="2" placeholder="Large"></textarea>
</div>

Helper text

Use .form-text below the field for short hints. Wire it to the textarea with aria-describedby so screen readers announce it.

A sentence or two. Visible on your public profile.
<div class="w-100" style="max-width: 24rem;">
  <label for="bioTextarea" class="form-label">Bio</label>
  <textarea class="textarea" id="bioTextarea" rows="3" aria-describedby="bioHelp"></textarea>
  <div id="bioHelp" class="form-text">A sentence or two. Visible on your public profile.</div>
</div>

Browser validation

Pair native constraint attributes (required, minlength, maxlength) with the :user-invalid pseudo. The browser fires it after the user interacts with the field, and clears it the moment the value satisfies the constraints.

Hit Submit with fewer than 10 characters to trigger :user-invalid. Type past 10 and the red clears on its own.
<form class="demo-stack w-100" style="max-width: 24rem;" onsubmit="event.preventDefault()">
  <div>
    <label for="reqMessage" class="form-label">Message</label>
    <textarea class="textarea" id="reqMessage" rows="3" required minlength="10" placeholder="At least 10 characters"></textarea>
    <div class="form-text">Hit Submit with fewer than 10 characters to trigger <code>:user-invalid</code>. Type past 10 and the red clears on its own.</div>
  </div>
  <button type="submit" class="btn btn--primary">Submit</button>
</form>

Server validation

Set aria-invalid="true" from your form library. The attribute is sticky, and Stisla just paints while it's present. Pair with a .form-text--error message tied via aria-describedby.

Please write at least 50 characters.
<div class="demo-stack w-100" style="max-width: 24rem;">
  <div>
    <label for="srvFeedback" class="form-label">Feedback</label>
    <textarea
      class="textarea"
      id="srvFeedback"
      rows="3"
      aria-invalid="true"
      aria-describedby="srvFeedbackError">Way too short.</textarea>
    <div id="srvFeedbackError" class="form-text form-text--error">Please write at least 50 characters.</div>
  </div>
</div>

Disabled & readonly

disabled blocks interaction and dims the field. readonly keeps the value selectable for copy but rejects edits. The bg shifts a tier so you can see at a glance that the field is selectable but not editable.

<div class="demo-stack w-100" style="max-width: 24rem;">
  <textarea class="textarea" rows="2" disabled>Disabled</textarea>
  <textarea class="textarea" rows="2" readonly>Readonly</textarea>
</div>

Customization

Eight variables retune .textarea independently of .input. Override on the field itself, on a parent scope, or on :root. --textarea-height acts as a min-height floor (the field grows past it as content fills in).

Variable Default Use
--textarea-radius var(--st-input-radius, var(--st-radius)) Corner radius; sizes pull --st-radius-sm / -lg
--textarea-height 2.25rem Min-height floor; the field grows past this with content. sm and lg reassign this
--textarea-padding-x calc(0.625rem * var(--st-density)) Horizontal padding; sm and lg reassign this
--textarea-font-size 0.875rem Text size; sm and lg reassign this
--textarea-bg var(--st-surface) Background; readonly shifts a tier
--textarea-color var(--st-foreground) Text color
--textarea-border var(--st-border) Border color; validation hooks flip this to --st-danger
--textarea-placeholder var(--st-muted-foreground) Placeholder text color