Getting StartedComponentsDesign TokensThemingTheme SynthesizerFrameworksAccessibilityUtilitiesServer RenderingBrowser SupportContributingChangelog App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip
ARC UI ARC Radiant Components
v4.2 Docs Components Tokens Synthesizer
Getting StartedFrameworksServer Rendering Design TokensThemingTheme SynthesizerTypographyUtilities All ComponentsAccessibilityBrowser SupportChangelogContributingStats App ShellAspect GridAuth ShellCenterContainerDashboard GridFloat BarInsetMasonryPage HeaderPage LayoutResizableResponsive SwitcherSectionSettings LayoutSplit PaneStatus BarStickyToolbar Anchor NavBottom NavBreadcrumbBreadcrumb MenuCommand BarDrawerFooterLinkMenubarNavigation MenuPage IndicatorPaginationRailScroll IndicatorScroll SpyScroll To TopSidebarSkip LinkStepper NavTabsTop BarTree View AccordionAspect RatioAvatarAvatar GroupCardCarouselCollapsibleColor SwatchCTA BannerDividerEmpty StateFeature CardIconImageImage CompareImage HotspotsInfinite ScrollLightboxMarqueeQR CodeScroll AreaSkeletonSpinnerStackVideoVirtual List Activity HeatmapAnimated NumberBadgeChartClockComparisonCountdown TimerData GridDescription ListDiffGaugeJSON TreeKanbanLevel MeterListMeterSparklineStatStepperTagTimelineUptimeValue CardWaveform BlockquoteCode BlockGradient TextHighlightKbdKeyboard MapMarkdownNumber FormatProseTerminalTextTime AgoTruncateTypewriter ButtonButton GroupCalendarCheckboxChipColor PickerComboboxCopy ButtonDate PickerDate Range PickerFieldsetFile UploadFormHotkeyIcon ButtonImage CropperInline EditInputInput GroupKnobLabelMasked InputMulti SelectNumber InputPassword InputPin InputRadio GroupRange SliderRatingSearchSegmented ControlSelectSignature PadSliderSortable ListSwitch GroupTag InputTextareaTheme ToggleTime PickerToggleTransfer ListTree Select AlertAnnouncementBannerCommand PaletteConfirmConnection StatusContext MenuConversationDialogDropdown MenuHover CardLoading OverlayNotification PanelPopoverProgressSheetToastTooltip

Textarea

Multi-line text input with integrated label, placeholder, resize control, and live character count that turns red at the limit.

Components Textarea
input hybrid
<arc-textarea>

Overview

Textarea is the dedicated multi-line text-entry component in ARC UI. It wraps a native `<textarea>` element with consistent styling, an integrated uppercase label, placeholder support, optional character counting, and validation feedback — all exposed through a declarative attribute API that works identically across every framework. Use Textarea whenever you need to collect more than a single line of freeform text: support ticket descriptions, comments, feedback forms, bio fields, or any content where the user benefits from seeing multiple lines at once. The `rows` prop controls the initial visible height, while the `resize` prop determines whether the user can drag the handle to expand the field vertically, horizontally, both, or not at all. When a `maxlength` is set, a live character counter appears below the field and automatically switches to an error color as the user approaches the limit. This gives immediate, accessible feedback without requiring any JavaScript on the consumer side. Pair Textarea with the Form component for coordinated validation, submission handling, and error summary across an entire form.

Guidelines

When to use

  • Always provide a `label` so the field is accessible to screen readers
  • Set `placeholder` to show an example value, not as a replacement for the label
  • Use `maxlength` when there is a backend or UX limit so users get immediate feedback
  • Choose an appropriate `rows` value that reflects the expected content length
  • Use `resize="none"` when the textarea sits inside a fixed-height layout that cannot reflow
  • Pair with the Form component for coordinated validation and submission
  • Use the `error` prop to surface server-side validation messages after submission

When not to use

  • Do not use Textarea for single-line fields like names or emails — use Input instead
  • Do not use placeholder text as the only label — it disappears on focus and fails accessibility
  • Do not set both `disabled` and `error` at the same time — the user cannot act on the error
  • Do not set extremely low `maxlength` values (under ~20) — use Input for short values instead
  • Avoid overriding the built-in border and focus styles with custom CSS — use design tokens instead
  • Do not hide the character counter when a maxlength is enforced — users need that feedback

Features

  • Integrated uppercase label rendered above the field with automatic `aria-labelledby` association
  • Live character counter that appears when `maxlength` is set and turns red at the limit
  • Configurable resize behavior via the `resize` prop: vertical, horizontal, both, or none
  • Adjustable initial height through the `rows` prop (defaults to 4)
  • Error state with a red border and an inline error message displayed below the field
  • Readonly mode that allows selection and copying but prevents edits
  • Disabled state that greys out the field and blocks all interaction
  • Keyboard-accessible with a visible focus ring following design tokens
  • Fires `arc-input` on every keystroke and `arc-change` on blur for flexible data binding
  • CSS custom properties for theming via shared design tokens

Preview

Usage

Layout and styling work without JavaScript via the HTML/CSS versions. Interactive features like events and state management require the Web Component or a framework wrapper.

<div style="width:100%;">
  <arc-textarea
    label="Describe your issue"
    placeholder="Please provide as much detail as possible..."
    rows="5"
    maxlength="500"
  ></arc-textarea>
</div>
import { Textarea } from '@arclux/arc-ui-react';

export default function Example() {
  return (
    <div style={{ width: '100%' }}>
      <Textarea
        label="Describe your issue"
        placeholder="Please provide as much detail as possible..."
        rows={5}
        maxlength={500}
      />
    </div>
  );
}
<script setup>
import { Textarea } from '@arclux/arc-ui-vue';
</script>

<template>
  <div style="width:100%;">
    <Textarea
      label="Describe your issue"
      placeholder="Please provide as much detail as possible..."
      :rows="5"
      :maxlength="500"
    />
  </div>
</template>
<script>
  import { Textarea } from '@arclux/arc-ui-svelte';
</script>

<div style="width:100%;">
  <Textarea
    label="Describe your issue"
    placeholder="Please provide as much detail as possible..."
    rows={5}
    maxlength={500}
  />
</div>
import { Component } from '@angular/core';
import { Textarea } from '@arclux/arc-ui-angular';

@Component({
  imports: [Textarea],
  template: `
    <div style="width:100%;">
      <arc-textarea
        label="Describe your issue"
        placeholder="Please provide as much detail as possible..."
        [rows]="5"
        [maxlength]="500"
      ></arc-textarea>
    </div>
  `,
})
export class SupportFormComponent {}
import { Textarea } from '@arclux/arc-ui-solid';

export default function Example() {
  return (
    <div style={{ width: '100%' }}>
      <Textarea
        label="Describe your issue"
        placeholder="Please provide as much detail as possible..."
        rows={5}
        maxlength={500}
      />
    </div>
  );
}
import { Textarea } from '@arclux/arc-ui-preact';

export default function Example() {
  return (
    <div style={{ width: '100%' }}>
      <Textarea
        label="Describe your issue"
        placeholder="Please provide as much detail as possible..."
        rows={5}
        maxlength={500}
      />
    </div>
  );
}
<div style="width:100%;">
  <arc-textarea
    label="Describe your issue"
    placeholder="Please provide as much detail as possible..."
    rows="5"
    maxlength="500"
  ></arc-textarea>
</div>
<!-- Auto-generated by @arclux/prism — do not edit manually -->
<!-- arc-textarea — self-contained, no external CSS needed -->
<div class="arc-textarea">

</div>

API

value string ''
The current text content of the textarea. Updated on every keystroke and emitted via arc-input and arc-change events.
name string ''
Form field name submitted with the value. Required for native form integration via ElementInternals.
placeholder string ''
Hint text displayed inside the field when it is empty. Use it to show example input -- never as a substitute for the label.
label string ''
Visible label rendered above the textarea in uppercase. Automatically linked to the field via aria-labelledby, ensuring screen readers announce it correctly.
rows number 4
The number of visible text rows that set the initial height of the textarea. Does not limit content length -- the user can scroll or resize beyond this height.
disabled boolean false
Prevents user interaction and applies a muted visual treatment at 40% opacity. The field value is excluded from form submission when disabled.
error string ''
Error message string. When non-empty, the textarea border turns red and the message is displayed below the field with role="alert" for screen reader announcement.
maxlength number 0
Maximum number of characters allowed. When set to a value greater than 0, a live counter appears below the field showing current length vs. limit, turning red when the limit is reached.
resize 'none' | 'vertical' | 'horizontal' | 'both' 'vertical'
Controls whether and in which direction the user can drag to resize the textarea. Defaults to vertical-only resizing.
readonly boolean false
Allows the user to select and copy text but prevents editing. The field has a subtle background change to indicate its read-only state.
size 'sm' | 'md' | 'lg' 'md'
Controls the textarea size. Options: 'sm', 'md', 'lg'.
autoResize boolean false
Automatically grows the textarea height to fit its content. Disables manual resize when enabled.
formAssociated boolean true
properties object { // flag(), unlike `disabled`. The exclusion in props.js is specifically // about form-associated *platform* semantics: a `disabled` content // attribute that is merely present makes the element actually disabled // per the HTML spec, and formDisabledCallback assigns the property back, // so no converter can win. Neither of these is platform-mapped — // `required` is enforced by _computeValidity() below and `readonly` by // each component's own interaction handlers — so the stock converter buys // nothing here and costs the usual bug: `required="false"` read as true, // blocking submission of a form the author meant to leave optional. // Finding #48's shape, across all 26 form controls at once. required: flag(false), readonly: flag(false), }
Lit merges static properties up the prototype chain, so every consumer gets these without declaring them. required participates in constraint validation below; readonly reflects for styling and is enforced by each component's interaction handlers (the mixin can't know which gestures mutate state).
autoValidates boolean true
Components that run their own constraint-validation logic (pattern checks, range checks) opt out of the automatic required sync by overriding this to false, and own the whole validity flag set instead.
form
validity
validationMessage
required boolean false

Methods

checkValidity() boolean
Whether the control currently satisfies its constraints, per the native constraint-validation API. Fires invalid on the element when it does not, and reports nothing to the user.
reportValidity() boolean
As checkValidity(), but also shows the browser's validation message against the control when it fails.

Events

arc-input detail: { value: string }
Fired on each keystroke with { value } detail
arc-change detail: { value: string }
Fired on blur when value has changed

See Also