icon

Morainev0.5.0

Textarea
formstextarea

Textarea

Multi-line text input with autoresize support and form field integration.

Import#

import { Textarea } from 'moraine'

Slot Structure#

Multi-line text input with optional header and footer slots.

root
├── header (optional)
├── input
└── footer (optional)

Examples#

Variants#

Outline/subtle/ghost/none visual variants.

function Variants() {
const VARIANTS: TextareaVariantName[] = ['outline', 'subtle', 'ghost', 'none']
type TextareaVariantName = Exclude<TextareaT.Variant['variant'], undefined>
return (
<div class="gap-3 grid lg:grid-cols-4 sm:grid-cols-2">
<For each={VARIANTS}>
{(variant) => <Textarea variant={variant} placeholder={`Variant: ${variant}`} rows={2} />}
</For>
</div>
)
}

Sizes#

Textarea size scale from xs to xl.

function Sizes() {
const SIZES: TextareaSizeName[] = ['xs', 'sm', 'md', 'lg', 'xl']
type TextareaSizeName = Exclude<TextareaT.Variant['size'], undefined>
return (
<div class="gap-3 grid lg:grid-cols-3 sm:grid-cols-2">
<For each={SIZES}>
{(size) => <Textarea size={size} placeholder={`Size: ${size}`} rows={2} />}
</For>
</div>
)
}

Autoresize#

Autoresize growth with maxrows.

function Autoresize() {
const [value, setValue] = createSignal('Type here to see autoresize...')
return (
<div class="max-w-xl space-y-3">
<Textarea
autoResize
maxRows={6}
value={value()}
onValueChange={(next) => setValue(String(next ?? ''))}
placeholder="Start typing..."
/>
<p class="text-xs text-muted-foreground">Characters: {value().length}</p>
</div>
)
}

Build composer-like surfaces using header/footer slots.

function HeaderFooter() {
const [composerValue, setComposerValue] = createSignal('Hello Moraine!')
return (
<div class="gap-6 grid lg:grid-cols-3">
<Textarea
placeholder="Ask, search or chat..."
header={
<>
<span class="font-semibold">Info text</span>
<Icon name="i-lucide-info" class="text-base ms-auto" />
</>
}
classes={{
header: 'border-b border-border',
input: 'min-h-24',
}}
/>
<Textarea
value={composerValue()}
onValueChange={(nextValue) => setComposerValue(String(nextValue ?? ''))}
placeholder="Write your message..."
autoResize
footer={
<>
<span>{composerValue().length}/280 characters</span>
<Button size="xs" class="ms-auto">
Send
</Button>
</>
}
classes={{
footer: 'b-(t border)',
input: 'min-h-24',
}}
/>
<Textarea
placeholder="console.log('Hello, world!');"
header={
<>
<Icon name="i-lucide-code" class="text-base" />
<span>script.js</span>
</>
}
footer={
<>
<span>Line 1, Column 1</span>
<span class="ms-auto">JavaScript</span>
</>
}
classes={{
header: 'b-(b border)',
footer: 'b-(t border)',
input: 'min-h-28',
}}
/>
</div>
)
}

API Reference#

Attributes#

Slotroot1 attribute
Textarea wrapper that owns header, textarea, footer, and autoresize state.

Data Attributes

1
Data AttributeDescription
data-focused
State or slot attribute exposed for styling hooks and selectors.

Props#

PropTypeDefaultDescription
autofocusboolean | undefinedfalse
Whether to automatically focus the textarea on mount.
autofocusDelaynumber | undefined0
Delay in milliseconds before focusing the textarea.
autoresizeboolean | undefined
autoResizeboolean | undefinedfalse
Whether the textarea should automatically resize based on content.
autoResizeDelaynumber | undefined0
Delay in milliseconds before triggering autoresize on mount.
childrenJSX.Element
Children elements, rendered inside the root below the textarea.
classClassValue
Class applied to the component root or trigger element.
classesTextareaT.Classes | undefined
defaultValueTextareaT.Value
The default value of the input (uncontrolled).
disabledboolean | undefinedfalse
Whether the input is disabled.
footerJSX.Element
Element to render below the textarea.
headerJSX.Element
Element to render above the textarea.
idstring | undefined
The ID of the input element.
maxLengthstring | number | undefined
Maximum character length for the textarea.
maxRowsnumber | undefined0
Maximum number of rows allowed during autoresize.
modelModifiersM | undefined
Modifiers for input processing (e.g., lazy, trim, number).
namestring | undefined
The name of the input element, used for form submission.
onBlurJSX.FocusEventHandlerUnion<HTMLTextAreaElement, FocusEvent> | undefined
Native blur event handler.
onChange((value: ModifierValue<M>) => void) | undefined
Callback when the textarea value change is committed.
onFocusJSX.FocusEventHandlerUnion<HTMLTextAreaElement, FocusEvent> | undefined
Native focus event handler.
onInputJSX.InputEventHandlerUnion<HTMLTextAreaElement, InputEvent> | undefined
Native input event handler.
onValueChange((value: ModifierValue<M>) => void) | undefined
Callback when the textarea value changes during input.
placeholderstring | undefined
Placeholder text for the textarea.
readOnlyboolean | undefinedfalse
Whether the input is read-only.
refJSX.HTMLElementTags["div"] extends { ref?: infer Ref; } ? Ref : never | undefined
requiredboolean | undefinedfalse
Whether the input is required.
rowsnumber | undefined3
Default number of rows.
size"xs" | "sm" | "md" | "lg" | "xl" | undefined
styleJSX.CSSProperties | undefined
stylesTextareaT.Styles | undefined
valueTextareaT.Value
The current value of the input (controlled).
variant"none" | "outline" | "ghost" | "subtle" | undefined