Textarea
ui-textarea wraps a native <textarea>. It starts at rows lines, grows with its content in browsers that support
field-sizing: content, and can be resized vertically. It is form-associated. Its value is submitted under its
name, and its validity is the inner textarea's validity.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Textarea demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-narrow {
width: min(100%, calc(var(--spacing) * 88));
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/textarea.html"></import-element>
<div class="demo-narrow">
<ui-textarea aria-label="Message" placeholder="Type your message here."></ui-textarea>
</div>
</body>
</html>Examples
With a label and description
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Textarea demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-narrow {
width: min(100%, calc(var(--spacing) * 88));
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/field.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/label.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/textarea.html"></import-element>
<div class="demo-narrow">
<ui-field>
<ui-label for="textarea-bio">Bio</ui-label>
<ui-textarea id="textarea-bio" rows="4" maxlength="160" placeholder="Tell us a little about yourself"></ui-textarea>
<ui-field-description>Up to 160 characters.</ui-field-description>
</ui-field>
</div>
</body>
</html>Disabled and read-only
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Textarea demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-narrow {
width: min(100%, calc(var(--spacing) * 88));
}
.demo-stack-tight {
display: grid;
gap: calc(var(--spacing) * 2);
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/textarea.html"></import-element>
<div class="demo-narrow demo-stack-tight">
<ui-textarea aria-label="Disabled" placeholder="Disabled" disabled></ui-textarea>
<ui-textarea aria-label="Release notes" value="Version 2.0 replaces the template syntax with native slots." readonly></ui-textarea>
</div>
</body>
</html>Invalid
invalid sets aria-invalid and a destructive border, for errors you detect yourself.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Textarea demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-narrow {
width: min(100%, calc(var(--spacing) * 88));
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/textarea.html"></import-element>
<div class="demo-narrow">
<ui-textarea aria-label="Feedback" value="Too short" invalid></ui-textarea>
</div>
</body>
</html>Character count
Listen for input to react while the user types.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Textarea demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/textarea.html"></import-element>
<import-element from="./textarea-count-demo.html"></import-element>
<textarea-count-demo></textarea-count-demo>
</body>
</html><custom-element name="textarea-count-demo">
<script>
const note = useState({ length: 0 });
function typed(field) {
note.length = field.value.length;
}
</script>
<style>
:host {
display: grid;
gap: calc(var(--spacing) * 2);
width: 100%;
max-width: calc(var(--spacing) * 96);
}
p {
margin: 0;
justify-self: end;
font-size: var(--text-xs);
color: var(--muted-foreground);
}
</style>
<ui-textarea aria-label="Note" maxlength="200" placeholder="Write a note" oninput="typed(this)"></ui-textarea>
<p><slot name="#note.length"></slot> / 200</p>
</custom-element>In a form
The text, including line breaks, is submitted under name. required and minlength block submission with the
browser's messages, and reset returns to the value attribute. Enter adds a new line and does not submit.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Textarea demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/button.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/textarea.html"></import-element>
<import-element from="./textarea-form-demo.html"></import-element>
<textarea-form-demo></textarea-form-demo>
</body>
</html><custom-element name="textarea-form-demo">
<script>
const result = useState({ text: "Submit the form to see its data." });
function submit(event) {
event.preventDefault();
result.text = [...new FormData(event.target)].map(([name, value]) => `${name}=${JSON.stringify(value)}`).join("\n");
}
function reset() {
result.text = "The form was reset.";
}
</script>
<style>
:host {
display: grid;
gap: calc(var(--spacing) * 4);
width: 100%;
max-width: calc(var(--spacing) * 96);
}
form {
display: grid;
gap: calc(var(--spacing) * 3);
}
.actions {
display: flex;
gap: calc(var(--spacing) * 2);
}
output {
display: block;
padding: calc(var(--spacing) * 3);
border-radius: var(--radius-md);
background: var(--muted);
font-family: var(--font-mono);
font-size: var(--text-xs);
white-space: pre-wrap;
}
</style>
<form onsubmit="submit(event)" onreset="reset()">
<ui-textarea name="review" aria-label="Review" rows="3" minlength="10" required placeholder="What did you think?"></ui-textarea>
<div class="actions">
<ui-button type="submit">Post review</ui-button>
<ui-button type="reset" variant="outline">Reset</ui-button>
</div>
</form>
<output><slot name="#result.text"></slot></output>
</custom-element>API
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
value |
string | "" |
Current text. The attribute is the initial and reset value. |
placeholder |
string | Placeholder text. | |
rows |
number | 3 |
Visible lines before the field grows. An integer of at least 1. |
minlength |
number | Minimum length. | |
maxlength |
number | Maximum length. | |
disabled |
boolean | false |
Disables the textarea. Also true inside a disabled <fieldset>. |
readonly |
boolean | false |
Makes the text read-only. |
required |
boolean | false |
The form is invalid while the text is empty. |
invalid |
boolean | false |
Sets aria-invalid="true" and the error style. Does not affect validity. |
aria-label |
string | Accessible name, passed to the inner textarea. Property name: label. |
Properties
| Property | Type | Description |
|---|---|---|
value |
string | Current text. Updated as the user types. Setting it updates the field. |
Events
| Event | Detail | Description |
|---|---|---|
input |
none | The inner textarea's native input event (composed). |
change |
none | Dispatched from the element (bubbling) when the inner textarea fires change, after it loses focus. |
CSS parts
| Part | Description |
|---|---|
textarea |
The inner native <textarea>. |
Forms
ui-textarea is form-associated and submits value under its name. Validity is mirrored from the inner
textarea, so required, minlength and maxlength take part in checkValidity() and reportValidity().
form.reset() restores the value attribute, and a disabled <fieldset> disables the field.
Accessibility
The host delegates focus to the inner textarea. Name it with aria-label, ui-label for or a wrapping <label>.