Specs: DESIGN.md line 444-458
<textarea
class="elv-textarea"
placeholder="Enter your message..."
aria-label="Message"
></textarea>
Include as much detail as possible to help us understand your needs.
Optional: Add any extra context that might be helpful.
<label class="elv-textarea-label" for="description">
Description <span class="elv-required">*</span>
</label>
<textarea
id="description"
class="elv-textarea"
placeholder="Provide a detailed description..."
required
aria-required="true"
></textarea>
<p class="elv-textarea-helper">
Helper text goes here
</p>
Maximum 500 characters
<div class="elv-textarea-wrapper">
<textarea
maxlength="500"
oninput="updateCount(this)"
></textarea>
<span class="elv-char-count">0 / 500</span>
</div>
<script>
function updateCount(textarea) {
const count = textarea.value.length;
const max = textarea.maxLength;
const counter = textarea.nextElementSibling;
counter.textContent = `${count} / ${max}`;
}
</script>
Focus state: 3px light purple outline (#c3bde5) — CRITICAL for accessibility
Simulated focus state (for reference):
.elv-textarea:focus {
outline: 3px solid #c3bde5; /* P40 */
outline-offset: 1px;
}
This field is required and must be at least 10 characters long.
Description must be at least 50 characters.
<textarea
class="elv-textarea elv-textarea--error"
aria-invalid="true"
aria-describedby="error-message"
></textarea>
<p id="error-message" class="elv-textarea-error" role="alert">
Error message text
</p>
This field is not currently editable.
<textarea class="elv-textarea" disabled></textarea>
↕️ Drag the bottom-right corner to resize vertically (horizontal resize is disabled)
Custom min-height can be set via inline styles or custom classes.
<!-- Default (min-height: 80px) -->
<textarea class="elv-textarea"></textarea>
<!-- Custom height -->
<textarea class="elv-textarea" style="min-height: 200px;"></textarea>
/* CSS */
.elv-textarea {
resize: vertical; /* Only vertical resize */
min-height: 80px; /* Default minimum */
}
<textarea
class="elv-textarea"
placeholder="Enter text..."
aria-label="Description"
></textarea>
<label class="elv-textarea-label" for="message">
Message <span class="elv-required">*</span>
</label>
<textarea
id="message"
class="elv-textarea"
required
aria-required="true"
></textarea>
<div class="elv-textarea-wrapper">
<textarea
class="elv-textarea"
maxlength="500"
oninput="updateCount(this)"
></textarea>
<span class="elv-char-count">0 / 500</span>
</div>
<textarea
class="elv-textarea elv-textarea--error"
aria-invalid="true"
aria-describedby="error-id"
></textarea>
<p id="error-id" class="elv-textarea-error" role="alert">
Error message
</p>
<textarea
class="elv-textarea"
style="min-height: 200px;"
></textarea>
<label for="id">aria-label when no visible label existsrequired attribute and aria-required="true"aria-invalid="true" and aria-describedby to link error messagesrole="alert" on error text for screen readersmaxlength to enforce limits, counter is visual only| Background | #fafafa (N5) |
| Border | 0.5px solid #b0afb6 (border-medium N40) |
| Border Radius | 8px (radius-sm) |
| Min Height | sm: 52px, md: 64px, lg: 64px |
| Padding | 12px (all sides) |
| Font | 16px / 400 / 24px line-height (Body) |
| Font Family | Figtree (var(--font-sans)) |
| Placeholder | #6f6d78 (text-nonessential) |
| Resize | vertical only (no horizontal) |
| Focus State | 3px solid #c3bde5 outline (P40), 1px offset |
| Error State | 2px border #eb2000 (R120), padding 11px |
| Error Message | 12px / 600, #b21800 (R140) |
| Disabled | Background #fcfcfd (N1), text #b0afb6 (N40), no resize |
| Label | 14px / 600, #201f23 (text-default) |
| Helper Text | 12px / 400, #6f6d78 (text-nonessential) |
| Character Count | 12px, #6f6d78, positioned bottom-right |