Textarea
A multi-line text input component for longer text entries
Variants
Code Svelte
1
2<script lang="ts">
3 import { Textarea, Label } from "@kareyes/aether";
4
5 let defaultValue = $state("");
6 let outlineValue = $state("");
7 let filledValue = $state("");
8 let ghostValue = $state("");
9 let underlineValue = $state("");
10</script>
11
12<div class="grid gap-6 md:grid-cols-2">
13 <div class="space-y-2">
14 <Label class="text-sm font-medium">Default</Label>
15 <Textarea bind:value={defaultValue} placeholder="Default variant..." />
16 </div>
17
18 <div class="space-y-2">
19 <Label class="text-sm font-medium">Outline</Label>
20 <Textarea variant="outline" bind:value={outlineValue} placeholder="Outline variant..." />
21 </div>
22
23 <div class="space-y-2">
24 <Label class="text-sm font-medium">Filled</Label>
25 <Textarea variant="filled" bind:value={filledValue} placeholder="Filled variant..." />
26 </div>
27
28 <div class="space-y-2">
29 <Label class="text-sm font-medium">Ghost</Label>
30 <Textarea variant="ghost" bind:value={ghostValue} placeholder="Ghost variant..." />
31 </div>
32
33 <div class="space-y-2">
34 <Label class="text-sm font-medium">Underline</Label>
35 <Textarea variant="underline" bind:value={underlineValue} placeholder="Underline variant..." />
36 </div>
37</div>Sizes
Code Svelte
1
2<script lang="ts">
3 import { Textarea, Label } from "@kareyes/aether";
4</script>
5
6<div class="grid gap-6">
7 <div class="space-y-2">
8 <Label class="text-sm font-medium">Small</Label>
9 <Textarea size="sm" placeholder="Small size textarea..." />
10 </div>
11
12 <div class="space-y-2">
13 <Label class="text-sm font-medium">Default</Label>
14 <Textarea size="default" placeholder="Default size textarea..." />
15 </div>
16
17 <div class="space-y-2">
18 <Label class="text-sm font-medium">Large</Label>
19 <Textarea size="lg" placeholder="Large size textarea..." />
20 </div>
21</div>Features
Grows from 3 to 8 rows automatically
0/200
Shows character count in corner
This field is required
0/100
Message is too long
Code Svelte
1
2<script lang="ts">
3 import { Textarea, Label } from "@kareyes/aether";
4
5 let autoResizeValue = $state("");
6 let withCountValue = $state("");
7</script>
8
9<div class="grid gap-6 md:grid-cols-2">
10 <div class="space-y-2">
11 <Label class="text-sm font-medium">Auto-Resize (3-8 rows)</Label>
12 <Textarea
13 bind:value={autoResizeValue}
14 autoResize
15 minRows={3}
16 maxRows={8}
17 placeholder="Type multiple lines to see auto-resize..."
18 />
19 </div>
20
21 <div class="space-y-2">
22 <Label class="text-sm font-medium">Character Counter (max 200)</Label>
23 <Textarea
24 bind:value={withCountValue}
25 maxLength={200}
26 showCount
27 placeholder="Type to see counter..."
28 />
29 </div>
30
31 <div class="space-y-2">
32 <Label class="text-sm font-medium">Disabled</Label>
33 <Textarea disabled value="This textarea is disabled" />
34 </div>
35
36 <div class="space-y-2">
37 <Label class="text-sm font-medium">Error State</Label>
38 <Textarea error={true} placeholder="This field has an error..." />
39 <p class="text-xs text-destructive">This field is required</p>
40 </div>
41
42 <div class="space-y-2">
43 <Label class="text-sm font-medium">Resize: None</Label>
44 <Textarea resize="none" placeholder="Cannot be manually resized..." />
45 </div>
46
47 <div class="space-y-2">
48 <Label class="text-sm font-medium">Resize: Both</Label>
49 <Textarea resize="both" placeholder="Resize in any direction..." />
50 </div>
51</div>Form Example
Code Svelte
1
2<script lang="ts">
3 import { Textarea, Button, Label } from "@kareyes/aether";
4
5 let formData = $state({
6 name: "",
7 email: "",
8 message: "",
9 });
10
11 function handleSubmit() {
12 console.log("Form submitted:", formData);
13 alert(\`Message submitted:\n\n\${formData.message}\`);
14 }
15</script>
16
17<form class="space-y-4" on:submit|preventDefault={handleSubmit}>
18 <div class="space-y-2">
19 <Label for="name">Name <span class="text-destructive">*</span></Label>
20 <input
21 id="name"
22 type="text"
23 bind:value={formData.name}
24 placeholder="John Doe"
25 required
26 />
27 </div>
28
29 <div class="space-y-2">
30 <Label for="message">Message <span class="text-destructive">*</span></Label>
31 <Textarea
32 id="message"
33 bind:value={formData.message}
34 variant="outline"
35 size="lg"
36 maxLength={500}
37 showCount
38 autoResize
39 minRows={4}
40 maxRows={10}
41 placeholder="Type your message here..."
42 required
43 />
44 </div>
45
46 <Button type="submit">Submit Message</Button>
47</form>Combined Features
0/100
0
Code Svelte
1
2<script lang="ts">
3 import { Textarea, Label } from "@kareyes/aether";
4</script>
5
6<div class="grid gap-6 md:grid-cols-2">
7 <div class="space-y-2">
8 <Label class="text-sm font-medium">Small + Filled + Counter</Label>
9 <Textarea
10 variant="filled"
11 size="sm"
12 maxLength={100}
13 showCount
14 placeholder="Compact with counter..."
15 />
16 </div>
17
18 <div class="space-y-2">
19 <Label class="text-sm font-medium">Large + Auto-Resize + Counter</Label>
20 <Textarea
21 variant="outline"
22 size="lg"
23 autoResize
24 minRows={3}
25 maxRows={6}
26 showCount
27 placeholder="Full-featured textarea..."
28 />
29 </div>
30</div>Textarea Variants & Features
Different styles and features for textarea fields
0/100
This field has an error
Maximum 200 characters
0/200
Automatically grows with content
Code Svelte
1
2<script lang="ts">
3 import { Textarea, Card, Field } from "@kareyes/aether";
4
5 let description = $state("");
6</script>
7
8<div class="grid gap-6 md:grid-cols-2">
9 <Card>
10 <Field label="Error State inside Field Textarea" error="This field has an error">
11 <Textarea
12 error={true}
13 maxLength={100}
14 showCount
15 placeholder="Message exceeds limit..."
16 />
17 </Field>
18 </Card>
19
20 <Card>
21 <Field label="Outline Textarea">
22 <Textarea placeholder="Enter your text..." variant="outline" />
23 </Field>
24 </Card>
25
26 <Card>
27 <Field label="With Character Counter" description="Maximum 200 characters">
28 <Textarea
29 bind:value={description}
30 placeholder="Enter your text..."
31 maxLength={200}
32 showCount
33 />
34 </Field>
35 </Card>
36
37 <Card>
38 <Field label="Auto-Resize" description="Automatically grows with content">
39 <Textarea placeholder="Start typing..." autoResize minRows={2} maxRows={6} />
40 </Field>
41 </Card>
42</div>Features
- Multiple Variants: default, outline, filled, ghost, underline
- Size Options: sm, default, lg
- Resize Control: none, vertical, horizontal, both
- Auto-Resize: Automatically grows/shrinks based on content
- Character Counter: Optional character count display
- Max Length: Limit input length with validation
- Full Type Safety: TypeScript support with proper types
- Accessibility: ARIA attributes and keyboard navigation
- Dark Mode: Built-in dark mode support
Usage
Basic Usage
<script lang="ts">
import { Textarea } from "@kareyes/aether";
let value = $state("");
</script>
<Textarea bind:value placeholder="Type here..." />
Variants
<!-- Default -->
<Textarea variant="default" />
<!-- Outline (thicker border) -->
<Textarea variant="outline" />
<!-- Filled (muted background) -->
<Textarea variant="filled" />
<!-- Ghost (no border) -->
<Textarea variant="ghost" />
<!-- Underline -->
<Textarea variant="underline" />
Sizes
<!-- Small -->
<Textarea size="sm" />
<!-- Default -->
<Textarea size="default" />
<!-- Large -->
<Textarea size="lg" />
Character Counter
<!-- Simple counter -->
<Textarea showCount />
<!-- With max length -->
<Textarea maxLength={200} showCount />
Auto-Resize
<!-- Auto-resize with min/max rows -->
<Textarea
autoResize
minRows={3}
maxRows={10}
/>
Resize Options
<!-- No resize -->
<Textarea resize="none" />
<!-- Vertical only (default) -->
<Textarea resize="vertical" />
<!-- Horizontal only -->
<Textarea resize="horizontal" />
<!-- Both directions -->
<Textarea resize="both" />
Full Example
<script>
import { Textarea } from "@kareyes/aether";
let message = $state("");
</script>
<div class="space-y-2">
<label for="message">Message</label>
<Textarea
id="message"
bind:value={message}
variant="outline"
size="lg"
maxLength={500}
showCount
autoResize
minRows={3}
maxRows={8}
placeholder="Type your message..."
/>
<p class="text-sm text-muted-foreground">
Your message will be reviewed by our team.
</p>
</div>
Error State
<Textarea
aria-invalid={true}
placeholder="This field has an error"
/>
<p class="text-sm text-destructive">This field is required</p>
Disabled State
<Textarea disabled value="Cannot edit this" />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value |
string |
undefined |
Bindable textarea value |
variant |
"default" | "outline" | "filled" | "ghost" | "underline" |
"default" |
Visual style variant |
size |
"sm" | "default" | "lg" |
"default" |
Size of the textarea |
resize |
"none" | "vertical" | "horizontal" | "both" |
"vertical" |
Resize behavior |
maxLength |
number |
undefined |
Maximum character length |
showCount |
boolean |
false |
Show character counter |
autoResize |
boolean |
false |
Auto-resize based on content |
minRows |
number |
undefined |
Minimum rows for auto-resize |
maxRows |
number |
undefined |
Maximum rows for auto-resize |
disabled |
boolean |
false |
Disable the textarea |
placeholder |
string |
undefined |
Placeholder text |
class |
string |
undefined |
Additional CSS classes |
ref |
HTMLTextAreaElement | null |
null |
Bindable element reference |
All standard HTML textarea attributes are supported.
Types
import type {
TextareaProps,
TextareaVariant,
TextareaSize,
TextareaResize
} from "@kareyes/aether";
Styling
The component uses Tailwind CSS and supports:
- Custom classes via the
classprop - Dark mode (automatically handled)
- Focus states with ring effect
- Error states via
aria-invalid - Disabled states
Accessibility
- Supports all standard textarea attributes
- Works with labels via
id - ARIA attributes for error states
- Keyboard navigation support
- Screen reader friendly
Notes
- When
autoResizeis enabled, theresizeprop is automatically set to"none" - Character counter appears in the bottom-right corner when
showCountis true - The component wraps the textarea in a
divwhenshowCountis enabled - Auto-resize uses
minRowsandmaxRowsto constrain height
Using Textarea with Field Component
The Field component provides labels, descriptions, and error handling. This is the recommended way to use Textarea in forms.
Basic Field Usage
<script lang="ts">
import { Field } from "@kareyes/aether";
import { Textarea } from "@kareyes/aether";
let bio = $state('');
</script>
<Field
label="Biography"
description="Tell us about yourself"
>
<Textarea bind:value={bio} placeholder="Write your bio here..." rows={4} />
</Field>
Field with Character Counter
<script lang="ts">
import { Field } from "@kareyes/aether";
import { Textarea } from "@kareyes/aether";
let description = $state('');
</script>
<Field
label="Description"
description="Maximum 200 characters"
>
<Textarea
bind:value={description}
maxLength={200}
showCount
placeholder="Enter description..."
/>
</Field>
Field with Auto-Resize
<script lang="ts">
import { Field } from "@kareyes/aether";
import { Textarea } from "@kareyes/aether";
let notes = $state('');
</script>
<Field
label="Notes"
description="Automatically grows with content"
>
<Textarea
bind:value={notes}
autoResize
minRows={2}
maxRows={8}
placeholder="Start typing..."
/>
</Field>
Field with Validation
<script lang="ts">
import { Field } from "@kareyes/aether";
import { Textarea } from "@kareyes/aether";
let message = $state('');
let errors = $state<Record<string, string>>({});
function validateMessage() {
if (!message) {
errors.message = 'Message is required';
} else if (message.length < 50) {
errors.message = 'Message must be at least 50 characters';
} else {
delete errors.message;
}
}
</script>
<Field
label="Message"
description="Minimum 50 characters"
required
error={errors.message}
>
<Textarea
bind:value={message}
placeholder="Type your message..."
aria-invalid={!!errors.message}
onblur={validateMessage}
rows={4}
/>
</Field>
Field with Different Variants
<script lang="ts">
import { Field } from "@kareyes/aether";
import { Textarea } from "@kareyes/aether";
let formData = $state({
bio: '',
comments: '',
feedback: '',
});
</script>
<div class="space-y-6">
<!-- Outline Variant -->
<Field
label="Bio"
description="Tell us about yourself"
>
<Textarea
variant="outline"
bind:value={formData.bio}
placeholder="Write your bio..."
rows={4}
/>
</Field>
<!-- Filled Variant with Counter -->
<Field
label="Comments"
description="Share your thoughts (max 500 characters)"
>
<Textarea
variant="filled"
bind:value={formData.comments}
maxLength={500}
showCount
rows={3}
/>
</Field>
<!-- Auto-resize with Underline -->
<Field
label="Feedback"
description="Your feedback helps us improve"
>
<Textarea
variant="underline"
bind:value={formData.feedback}
autoResize
minRows={2}
maxRows={6}
placeholder="Start typing..."
/>
</Field>
</div>
Complete Form Example
<script lang="ts">
import { FieldPrimitives,Field } from "@kareyes/aether";
import { Textarea } from "@kareyes/aether";
import { Button } from "@kareyes/aether";
let formData = $state({
title: '',
description: '',
additionalNotes: '',
});
let errors = $state<Record<string, string>>({});
function handleSubmit(e: Event) {
e.preventDefault();
errors = {};
if (!formData.description) {
errors.description = 'Description is required';
} else if (formData.description.length < 50) {
errors.description = 'Description must be at least 50 characters';
}
if (Object.keys(errors).length === 0) {
console.log('Form submitted:', formData);
}
}
</script>
<form onsubmit={handleSubmit} class="space-y-6">
<FieldPrimitives.Set>
<FieldPrimitives.Legend>Project Details</FieldPrimitives.Legend>
<FieldPrimitives.Description>
Provide information about your project
</FieldPrimitives.Description>
<FieldPrimitives.Separator />
<FieldPrimitives.Group class="gap-6">
<Field
label="Description"
description="Detailed description of your project (minimum 50 characters)"
required
error={errors.description}
>
<Textarea
bind:value={formData.description}
variant="outline"
size="lg"
maxLength={1000}
showCount
autoResize
minRows={4}
maxRows={10}
placeholder="Describe your project..."
aria-invalid={!!errors.description}
/>
</Field>
<Field
label="Additional Notes"
description="Any other information you'd like to share"
>
<Textarea
bind:value={formData.additionalNotes}
variant="filled"
autoResize
minRows={3}
maxRows={6}
placeholder="Optional notes..."
/>
</Field>
</FieldPrimitives.Group>
<div class="flex gap-4 pt-4">
<Button type="submit">Submit</Button>
<Button type="button" variant="outline">Cancel</Button>
</div>
</FieldPrimitives.Set>
</form>