Skip to content
omaris

Inputs

Textarea

Multi-line text field.

import { Textarea } from 'omaris'
Learn

Examples

Basic

Same frame and states as Input, with rows instead of a height — for a note, an address, anything longer than a line.

The driver sees this.
<script lang="ts">	import { Textarea } from 'omaris';​	let notes = $state('');</script>​<Textarea	class="w-96 max-w-full"	label="Delivery notes"	placeholder="Gate code, floor, anything the driver should know"	supportingText="The driver sees this."	bind:value={notes}/>

Autosize and counter

autosize grows the field with its content, up to maxRows, using a hidden mirror element — so the caret never scrolls out of view mid-sentence.

28/280
<script lang="ts">	import { Textarea } from 'omaris';​	let bio = $state('Ships dashboards from Erbil.');</script>​<div class="flex w-full max-w-md flex-col gap-6">	<Textarea label="Bio" autosize rows={2} maxRows={8} counter maxlength={280} bind:value={bio} />	<Textarea label="Fixed at 3 rows" rows={3} value="This one does not grow." /></div>

States

The supporting line becomes the error text when the field is invalid, so the reason is under the field and not in a toast.

At least 20 characters.
<script lang="ts">	import { Textarea } from 'omaris';</script>​<Textarea class="w-72 max-w-full" label="Required" required placeholder="Say something" /><Textarea	class="w-72 max-w-full"	label="Invalid"	invalid	value="Too short"	supportingText="At least 20 characters."/><Textarea class="w-72 max-w-full" label="Disabled" disabled value="Read only" />

When to use it

Use it for

  • Text that runs past a line: delivery notes, a description, a reply, an address.
  • A composer. autosize with rows={1} and a maxRows grows one line at a time. bind:lines swaps in a send button or shows a "shift+enter for a new line" hint.
  • A hard limit the person should see coming. Pass counter with maxlength.

Not for

  • One line, like a title, a name or a URL → Text Field.
  • Bold, a list, a link → Rich Text Editor.
  • Code, JSON, a query → Code Editor with lang. It indents, closes brackets and colours.
  • Chat text with emoji → still this, with an Emoji Button beside it.

Do

  • Match the Input next to it: same variant, same size. They share a frame and line up without adjustment.
  • Set rows to the length you expect: 2 for a note, 6 for a description. The default 3 is a guess.
  • Give autosize a maxRows, or a pasted essay pushes the submit button off the screen.
  • Put the reason in supportingText and set invalid. The helper line becomes the error line.

Don't

  • Autosize inside a grid of cards. The row below moves every time a line is added. Fix rows there and let it scroll.
  • Expect the resize grip with autosize. The box sizes itself, so the grip is removed. Without autosize the grip is on, vertical only.
  • Use the placeholder for instructions needed after typing starts. That is supportingText.

Quick reference

variant
  • outline (default)
  • filled
  • ghost
size
  • sm
  • default (default)
  • lg

--field-line is the line box the row maths are done in, so it has to be a real length rather than normal.

API

Textarea

Multi-line text field.

Shares the Input's frame — same three variants, same focus bloom, same label/supporting-text layout — so a form mixing the two lines up without fiddling.

autosize turns it into a composer: the box tracks how many lines the text actually occupies and grows a line at a time, smoothly, instead of scrolling inside a fixed rectangle. It starts at rows, never goes below it, and stops at maxRows — past which it scrolls like a normal textarea. Height comes from a mirror of the text rather than from poking the element's own height between measurements, so the growth can be transitioned without the flicker that trick usually brings.

import { Textarea } from 'omaris'

Parts

Every element this renders is reachable from outside. Pass Tailwind for one part as classes={{ part: '…' }}; class covers the root and is merged last, so it always wins.

root
No description in the source yet.
field
No description in the source yet.
well
Holds the control and, when autosizing, the mirror behind it.
control
No description in the source yet.
mirror
An invisible copy of the text, laid over the control at the same width and typography. Its height is the height the control wants — measured without ever resizing the control itself.
label
No description in the source yet.
support
No description in the source yet.
counter
No description in the source yet.

Props

variant

Defaults to 'outline'

TextareaVariant
outline
filled
ghost
size

Defaults to 'default'

TextareaSize
sm
default
lg
label
string
required
boolean

Inside a Field, defaults to the field's.

supportingText
string
invalid
boolean

Inside a Field, defaults to the field's.

value bindable

Defaults to ''

string
counter

Defaults to false

boolean

Live n/maxlength count beside the supporting text.

autosize

Defaults to false

boolean

Grow with the text. The box starts at rows, gains a line as the text takes one, and scrolls once it reaches maxRows.

rows

Defaults to 3

number

Starting height, in lines — and the floor when autosize.

maxRows
number

Ceiling for autosize, in lines. Past this it scrolls.

lines bindable

Defaults to 1

number

Lines the text currently occupies. Bindable, and read-only in practice — useful for a "shift+enter for a new line" hint or for swapping a send button in once the composer has something in it.

class
string
classes
TextareaClasses

Per-part Tailwind overrides. class still covers the root.

supporting
Snippet

Richer supporting text — a link, a hint.

ref bindable

Defaults to null

HTMLTextAreaElement | null