AvesraAvesrabeta

TextArea

Primitive multiline text input. Apply av-textarea to a native <textarea> element. Accepts standard HTML attributes and implements ControlValueAccessor for Angular forms.

Import

import { AvTextareaComponent } from '@avesra/angular';

For labels, descriptions, and validation errors, compose with av-label, av-description, and av-field-error. For form-level validation and submission, see Form.

Usage

import { Component } from '@angular/core';
import { AvLabelComponent, AvTextareaComponent } from '@avesra/angular';

@Component({
  selector: 'app-textarea-basic-demo',
  imports: [AvTextareaComponent, AvLabelComponent],
  host: { class: 'flex w-full max-w-sm flex-col gap-1' },
  template: `<label av-label for="textarea-basic">Description</label>
      <textarea
        av-textarea
        id="textarea-basic"
        placeholder="Describe your product"
        rows="4"
        aria-label="Description"
      ></textarea>`,
})
export class TextareaBasicDemo {}

Anatomy

TextArea uses the av-textarea attribute selector on a native <textarea> element.

<textarea av-textarea rows="4" placeholder="Tell us about yourself"></textarea>

Variants

The TextArea component supports two visual variants:

  • primary (default) — Standard styling with shadow, suitable for most use cases
  • secondary — Lower emphasis variant without shadow, suitable for use in Surface components
import { Component } from '@angular/core';
import { AvTextareaComponent } from '@avesra/angular';

@Component({
  selector: 'app-textarea-variants-demo',
  imports: [AvTextareaComponent],
  host: { class: 'flex w-full max-w-96 flex-col gap-4' },
  template: `<textarea av-textarea full-width placeholder="Primary textarea" variant="primary" rows="3"></textarea>
      <textarea av-textarea full-width placeholder="Secondary textarea" variant="secondary" rows="3"></textarea>`,
})
export class TextareaVariantsDemo {}

In Surface

When used inside a Surface component, use variant="secondary" for the lower-emphasis style that fits surface backgrounds.

import { Component } from '@angular/core';
import { AvSurfaceComponent, AvTextareaComponent } from '@avesra/angular';

@Component({
  selector: 'app-textarea-on-surface-demo',
  imports: [AvTextareaComponent, AvSurfaceComponent],
  host: { class: 'w-full max-w-sm' },
  template: `
<div av-surface class="w-full rounded-3xl p-6">
  <textarea
    av-textarea
    full-width
    placeholder="Describe your product"
    variant="secondary"
    rows="4"
  ></textarea>
</div>
`,
})
export class TextareaOnSurfaceDemo {}

Full Width

import { Component } from '@angular/core';
import { AvSurfaceComponent, AvTextareaComponent } from '@avesra/angular';

@Component({
  selector: 'app-textarea-full-width-demo',
  imports: [AvTextareaComponent, AvSurfaceComponent],
  host: { class: 'flex w-full max-w-96 flex-col gap-4' },
  template: `<textarea av-textarea full-width placeholder="Full width textarea" rows="4"></textarea>
      <div av-surface class="w-full rounded-3xl p-6">
        <textarea
          av-textarea
          full-width
          placeholder="Full width textarea on surface"
          variant="secondary"
          rows="4"
        ></textarea>
      </div>`,
})
export class TextareaFullWidthDemo {}

Controlled

Bind with [(ngModel)] or reactive forms — TextArea implements ControlValueAccessor.

Characters: 0 / 280

import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AvDescriptionComponent, AvTextareaComponent } from '@avesra/angular';

@Component({
  selector: 'app-textarea-controlled-demo',
  imports: [FormsModule, AvTextareaComponent, AvDescriptionComponent],
  host: { class: 'flex w-full max-w-sm flex-col gap-2' },
  template: `
<textarea
  av-textarea
  full-width
  aria-label="Announcement"
  aria-describedby="textarea-controlled-description"
  placeholder="Compose an announcement..."
  rows="4"
  [(ngModel)]="value"
></textarea>
<p av-description id="textarea-controlled-description">
  Characters: {{ value.length }} / 280
</p>
`,
})
export class TextareaControlledDemo {
  value = '';
}

Rows and Resizing

Control visible height with the native rows attribute. Add a resize utility such as resize-y when vertical resizing should be allowed.

import { Component } from '@angular/core';
import { AvLabelComponent, AvTextareaComponent } from '@avesra/angular';

@Component({
  selector: 'app-textarea-rows-demo',
  imports: [AvTextareaComponent, AvLabelComponent],
  host: { class: 'flex w-full max-w-sm flex-col gap-4' },
  template: `
<div class="flex flex-col gap-2">
  <label av-label for="textarea-rows-3">Short feedback</label>
  <textarea
    av-textarea
    full-width
    id="textarea-rows-3"
    aria-label="Short feedback"
    placeholder="This week's highlights..."
    rows="3"
  ></textarea>
</div>
<div class="flex flex-col gap-2">
  <label av-label for="textarea-rows-6">Detailed notes</label>
  <textarea
    av-textarea
    full-width
    id="textarea-rows-6"
    class="resize-y"
    aria-label="Detailed notes"
    placeholder="Write out the full meeting notes..."
    rows="6"
  ></textarea>
</div>
`,
})
export class TextareaRowsDemo {}

Customization

Tailwind CSS

<textarea
  av-textarea
  class="h-28 w-full max-w-xs rounded-xl border border-border/80
    bg-surface text-sm shadow-sm ring-1 ring-black/5
    placeholder:text-muted
    focus-visible:ring-2 focus-visible:ring-neutral-400/25"
  aria-label="Notes"
  placeholder="Add a note..."
  rows="4"
></textarea>

Global CSS

Override the shared .av-textarea class once with Tailwind's @layer components.

@layer components {
  .av-textarea {
    @apply rounded-xl border border-border bg-surface px-4 py-3 text-sm leading-6 shadow-sm;

    &:hover,
    &[data-hovered="true"] {
      @apply bg-surface-secondary border-border/80;
    }

    &:focus-visible,
    &[data-focus-visible="true"] {
      @apply border-accent ring-2 ring-accent/20;
    }

    &[data-invalid="true"] {
      @apply border-danger bg-danger-soft text-danger;
    }
  }
}

Styling Reference

Avesra follows the BEM methodology so variants and states stay reusable and easy to customize.

CSS Classes

Base Classes

  • .av-textarea — Underlying <textarea> element styling
  • .av-textarea--primary — Primary visual variant (default)
  • .av-textarea--secondary — Secondary visual variant
  • .av-textarea--full-width — Full-width layout

Interactive States

  • Hover: :hover or [data-hovered="true"]
  • Focus Visible: :focus-visible or [data-focus-visible="true"]
  • Invalid: [data-invalid="true"]
  • Disabled: :disabled or [aria-disabled="true"]

API Reference

TextArea accepts standard HTML <textarea> attributes (such as rows, placeholder, readonly, name, maxlength) plus the following Angular inputs. Bind values with [(ngModel)] or reactive forms via ControlValueAccessor.

PropTypeDefaultDescription
variant'primary' | 'secondary''primary'Visual variant. `primary` is the default style with shadow. `secondary` is a lower-emphasis variant without shadow, suitable for surfaces.
full-widthbooleanfalseWhether the textarea should take the full width of its container.
disabledbooleanfalseDisables the textarea.
invalidbooleanfalseMarks the textarea as invalid (`aria-invalid` / `data-invalid`).

For field-level validation UI, compose with av-label, av-description, av-field-error, and optionally Form.

Made with ❤ by SyntaxHertz. Open source and available on GitHub.