K

Forms

Textarea

Multi-line text, with the row count and the resize behaviour it is given.

Textarea preview
On this page

Multi-line text. Reach for Textarea whenever the answer is a sentence or more — a note, a description, an address. For one line use TextInput; for text the user should be able to format, use the rich or markdown editor instead.

use NyonCode\WireForms\Components\Textarea;

How It Works

A textarea is a field: a string at its state path, validated like any other. It renders a plain <textarea> — no editor, no toolbar — which is exactly why it is the right default for free text you do not want marked up.

rows() sets the starting height, not a limit. It emits the HTML rows attribute and defaults to 3. A user can always drag the corner to make it bigger; nothing here stops them.

autosize() takes the height over. It adds a tiny Alpine handler that sets style.height to the content's scrollHeight on every input — and, because it also runs on x-init, from the first paint. An inline height beats the rows attribute, so with autosize on, rows() only governs the moment before Alpine boots. The box grows and shrinks with the text.

cols() is almost never what you want. It emits the cols attribute, but the element carries w-full, and a CSS width beats an HTML column count. Use columnSpan() on a Grid to make a textarea narrower, not cols().

spellcheck() is three-valued. null — the default — omits the attribute entirely and lets the browser and OS decide. true and false force it. This is the difference between "no opinion" and "off", and only the second one stops a browser underlining a field full of product codes.

minLength() / maxLength() do two things at once. They emit the HTML attributes and add the min / max validation rules, so the limit is enforced on the server as well as hinted in the browser. They are also checked at build time: a negative length, or a minLength above the maxLength, throws FormConfigurationException when the form is composed rather than failing quietly at validation.

Basic Usage

Textarea::make('description')
->label('Description')
->rows(5)
->maxLength(1000)

Growing With The Text

Textarea::make('notes')
->autosize()
->rows(3) // the height before Alpine takes over

Turning Spellcheck Off

Textarea::make('sku_list')
->label('SKUs, one per line')
->spellcheck(false)
->autosize()

Live Updates

A textarea on live() sends a round trip per keystroke, so give it a debounce:

Textarea::make('bio')
->live()
->debounce(500)

Extended Example

An article form in a real Livewire host — a one-line title, a short summary with a hard limit, and a body that grows as it is typed:

use Livewire\Component;
use NyonCode\WireForms\Components\TextInput;
use NyonCode\WireForms\Components\Textarea;
use NyonCode\WireForms\Forms\Form;
use NyonCode\WireForms\Forms\WithForms;
 
class EditArticle extends Component
{
use WithForms;
 
public ?array $data = [];
 
public function form(Form $form): Form
{
return $form
->statePath('data')
->model(Article::class)
->schema([
TextInput::make('title')->required(),
 
Textarea::make('summary')
->label('Summary')
->helperText('Shown in listings and search results.')
->rows(2)
->maxLength(160)
->required(),
 
Textarea::make('body')
->label('Body')
->autosize()
->rows(8)
->minLength(50),
])
->successMessage('Article saved');
}
 
public function save(): void
{
$this->form->save();
}
}

The summary is capped at 160 characters in the browser and on the server; the body cannot be shorter than 50 and grows as it is written.

Textarea API

->rows(int $rows) // starting height in rows — default 3
->cols(?int $cols) // the HTML cols attribute; w-full usually wins — prefer columnSpan()
->autosize(bool $condition = true) // grow and shrink with the content — default false
->spellcheck(?bool $condition = true) // true|false forces it; null (default) leaves it to the browser
->minLength(?int $length) // HTML attribute AND the `min` validation rule
->maxLength(?int $length) // HTML attribute AND the `max` validation rule
->getRows(): int
->getCols(): ?int
->isAutosize(): bool
->getSpellcheck(): ?bool
->getMinLength(): ?int
->getMaxLength(): ?int

Labels, help text, placeholder, prefixes, visibility, defaults, validation and live() are shared by every field — see Common Field API.