Skip to content

TextArea ​

TextArea is the multi-line counterpart of Input: the same variants, the same four sizes, and the same behaviour inside a field. It is the control, not the field — for a label, a description and a validation state, put it inside a TextField exactly as you would an input.

ts
import { TextArea } from "ropav";
variant
size
resize
template
<TextArea placeholder="What changed in this release?" />

Inside a field ​

A TextField drives whatever control it finds, so a textarea in place of an Input needs nothing else: the Label is already associated with it, a Description is already referenced by it, and variant and size come from the field. A prop set on the textarea itself wins over what the field supplies.

Markdown is rendered on the changelog page.
textarea-field.vue
vue
<script setup lang="ts">
import { Description, Label, TextArea, TextField } from "ropav";
</script>

<template>
  <TextField class="field" name="notes" size="sm" variant="secondary">
    <Label>Release notes</Label>
    <TextArea full-width placeholder="What changed in this release?" rows="4" />
    <Description>Markdown is rendered on the changelog page.</Description>
  </TextField>
</template>

<style scoped>
.field {
  width: 100%;
  max-width: var(--rp-container-sm);
}
</style>

Only value, variant, size, fullWidth, placeholder, autosize, minRows, maxRows and resize are declared. Everything else a <textarea> accepts — rows, maxlength, spellcheck, autocomplete — arrives by attribute fallthrough and lands on the element.

Autosize ​

autosize grows the control with what is typed. minRows and maxRows bound that growth; without a max it keeps going. Native resize is forced off while it is on, so the drag handle cannot fight the measured height.

textarea-autosize.vue
vue
<script setup lang="ts">
import { TextArea } from "ropav";
</script>

<template>
  <div class="stack">
    <TextArea
      autosize
      class="field"
      :max-rows="6"
      :min-rows="2"
      placeholder="Grows from 2 rows up to 6"
    />
    <TextArea autosize class="field" :min-rows="3" placeholder="Grows without a cap" />
  </div>
</template>

<style scoped>
.stack {
  display: flex;
  flex-direction: column;
  gap: calc(var(--rp-spacing) * 4);
}

.field {
  width: 100%;
  max-width: var(--rp-container-sm);
}
</style>

Enable resize ​

By default, resize is none; to enable it, set the resize prop to vertical or both.

textarea-resize.vue
vue
<script setup lang="ts">
import { TextArea } from "ropav";
</script>

<template>
  <div class="stack">
    <TextArea class="field" placeholder="Resize is none by default" :rows="3" />
    <TextArea class="field" placeholder="Drag the bottom edge" resize="vertical" :rows="3" />
    <TextArea class="field" placeholder="Drag any edge" resize="both" :rows="3" />
  </div>
</template>

<style scoped>
.stack {
  display: flex;
  flex-direction: column;
  gap: calc(var(--rp-spacing) * 4);
}

.field {
  width: 100%;
  max-width: var(--rp-container-sm);
}
</style>

Holding the value ​

Setting value takes the control over from the surrounding field, so the caller owns the text even inside a TextField. Pair it with change, or with v-model:value, or the text is pinned: the element is put back to what the caller holds after every input, including the reset value a form submission would restore.

API ​

PropTypeDefaultDescription
autosizebooleanfalseWhether the control grows with its content. minRows and maxRows only apply when this is set. Native resize is forced off while it is, so the drag handle cannot fight the measured height.
fullWidthboolean—Whether the control stretches to fill its container.
maxRowsnumber—Maximum visible rows while autosize is set. Ignored otherwise. Absent, the control grows without a cap.
minRowsnumber—Minimum visible rows while autosize is set. Ignored otherwise. Written through to the native rows attribute so the first paint is already that tall.
placeholderstring—Placeholder shown while the control is empty. Declared so it can also be set here rather than only on the field; every other native attribute arrives by attribute fallthrough.
resize"none" | "vertical" | "both""none"Whether the pointer can drag the edge. none by default; vertical or both opt in. Ignored while autosize is set.
size"xs" | "sm" | "md" | "lg""md"How much room the text is given, matching a field of the same size. Taken from the surrounding field when unset.
valuestring—Text in the control. Set here it takes the control over from the surrounding field, so the caller owns the value even inside a TextField — exactly as a value prop does in React. Without a listener to go with it the text is pinned.
variant"primary" | "secondary""primary"Visual variant. Taken from the surrounding field when unset.
EventPayload
changestring
update:valuestring