# Text Area

A multi-line text field framed by a bordered group, with configurable text size, surface, and resize behavior.

## Installation

```tsx
import { TextArea, TextAreaGroup } from "@makeplane/propel/components/text-area";
```
## Usage

```tsx
import { TextArea, TextAreaGroup } from "@makeplane/propel/components/text-area";

export default function BasicDemo() {
  return (
    <TextAreaGroup resize="vertical">
      <TextArea
        size="lg"
        surface="field"
        aria-label="Comment"
        placeholder="Leave a comment..."
        rows={4}
      />
    </TextAreaGroup>
  );
}
```
## Examples

### Sizes

`size` sets the type, one rung below the frame it sits in — `md` 12 / `lg` 13 / `xl` 14 /
`2xl` 16 px. Prose in a composer reads smaller than a single-line value at the same nominal
size, which is why the two scales are offset. On the `field` surface each step also pins the
frame's minimum height.

```tsx
import { TextArea, TextAreaGroup } from "@makeplane/propel/components/text-area";

const SIZES = ["md", "lg", "xl", "2xl"] as const;

export default function SizesDemo() {
  return (
    <div className="flex flex-col gap-4">
      {SIZES.map((size) => (
        <TextAreaGroup key={size} resize="vertical">
          <TextArea
            size={size}
            surface="field"
            rows={2}
            aria-label={`Comment (${size})`}
            defaultValue={`The ${size} size sizes the value text.`}
          />
        </TextAreaGroup>
      ))}
    </div>
  );
}
```

### Surfaces

`surface` picks the control presentation: `field` pairs with the bordered `TextAreaGroup` frame, `embedded` pads itself inside a composer frame that owns the chrome, and `inline` hugs its line height for compact single-row composers.

```tsx
import { TextArea, TextAreaGroup } from "@makeplane/propel/components/text-area";

export default function SurfacesDemo() {
  return (
    <div className="flex w-80 flex-col gap-4">
      <TextAreaGroup resize="none">
        <TextArea
          size="lg"
          surface="field"
          aria-label="Field comment"
          rows={2}
          defaultValue="The field surface sits inside the TextAreaGroup frame."
        />
      </TextAreaGroup>
      <div className="flex w-full flex-col overflow-clip rounded-xl border border-subtle-1 bg-layer-2">
        <TextArea
          size="lg"
          surface="embedded"
          aria-label="Embedded comment"
          rows={2}
          defaultValue="The embedded surface pads itself inside a composer frame."
        />
      </div>
      <div className="flex items-center gap-2 rounded-lg border border-subtle-1 bg-layer-2 px-3 py-2">
        <TextArea
          size="lg"
          surface="inline"
          aria-label="Inline comment"
          rows={1}
          defaultValue="The inline surface hugs a compact row."
        />
      </div>
    </div>
  );
}
```

### Resize

`TextAreaGroup`'s `resize` prop controls the native drag handle on the bordered frame (so growth
carries the chrome): `none` locks the size, `vertical` allows height changes, and `both` frees both
axes. The leaf itself is never resizable.

```tsx
import { TextArea, TextAreaGroup } from "@makeplane/propel/components/text-area";

const RESIZES = ["none", "vertical", "both"] as const;

const RESIZE_COPY = {
  none: "No resize handle — the textarea keeps its size.",
  vertical: "Drag the corner handle to grow the textarea vertically.",
  both: "Drag the corner handle to grow the framed textarea in both directions.",
} as const;

export default function ResizeDemo() {
  return (
    <div className="flex flex-col gap-4">
      {RESIZES.map((resize) => (
        <TextAreaGroup key={resize} resize={resize}>
          <TextArea
            size="lg"
            surface="field"
            rows={2}
            aria-label={`Comment (resize ${resize})`}
            defaultValue={RESIZE_COPY[resize]}
          />
        </TextAreaGroup>
      ))}
    </div>
  );
}
```

### Auto resize

`autoResize` grows the control with its value, using the size min-height as the floor. Pair it with
`TextAreaGroup` `resize="none"` so the native drag handle does not fight the content height.
`maxRows` caps the visible lines; further content scrolls.

```tsx
import { TextArea, TextAreaGroup } from "@makeplane/propel/components/text-area";

export default function AutoResizeDemo() {
  return (
    <TextAreaGroup resize="none">
      <TextArea
        size="lg"
        surface="field"
        autoResize
        maxRows={8}
        rows={2}
        aria-label="Comment"
        placeholder="Type to grow the field…"
      />
    </TextAreaGroup>
  );
}
```

### With description

```tsx
import { Field, FieldDescription, FieldLabel } from "@makeplane/propel/components/field";
import { TextArea, TextAreaGroup } from "@makeplane/propel/components/text-area";

export default function WithDescriptionDemo() {
  return (
    <Field name="summary">
      <FieldLabel size="lg" inset={false}>
        Project summary
      </FieldLabel>
      <TextAreaGroup resize="vertical">
        <TextArea
          size="lg"
          surface="field"
          rows={3}
          placeholder="Describe what this project is about..."
        />
      </TextAreaGroup>
      <FieldDescription size="lg">Visible to everyone in the workspace.</FieldDescription>
    </Field>
  );
}
```
## API Reference

### TextArea

Multi-line text field that automatically works inside `Field`. Base UI's `Field.Control` behavior
grafted onto the styled `elements` `TextArea` element (rule 1a) — behavior part outer, styled
part as the render target. Base UI ships no textarea control, so `Field.Control` renders the
styled `<textarea>` directly (this replaces the former `base/text-area` wrapper). Pair the
`field` surface with `TextAreaGroup`, which owns the native `resize` handle. `autoResize` grows
the control with its value; the ready-made `TextAreaField` turns the native handle off when it is
set.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `size` (required) | `"md" \| "lg" \| "xl" \| "2xl"` | — | Text size for the textarea value. |
| `surface` (required) | `"inline" \| "field" \| "embedded"` | — | Control presentation for standalone fields or embedded composer surfaces. |
| `defaultValue` | `string \| number \| readonly string[]` | — | The default value of the textarea. Use when uncontrolled. |
| `value` | `string \| number \| readonly string[]` | — | The value of the textarea. Use when controlled. |
| `autoResize` | `boolean` | `false` | Grow the control with its value, using the size min-height as the floor. Pair the `field` surface with `TextAreaGroup` `resize="none"` so the native drag handle does not fight content-driven height. |
| `maxRows` | `number` | — | Maximum visible lines when `autoResize` is set. Further lines scroll inside the control. Unbounded when omitted. |

### TextAreaGroup

The bordered frame that wraps a `field`-surface `TextArea` leaf. Owns the border, radius,
focus/error border treatments, and the native `resize` handle so growth carries the chrome with
the content. Children should be that single leaf only — the field surface is `min-w-full`, so a
sibling inside the frame overflows. Put attach/submit controls outside the group, or use the
`embedded` / `inline` surfaces (no group) for composer rows. Pair `autoResize` on the leaf with
`resize="none"` so the native drag handle does not fight content-driven height.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, {}>` | — | Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |
| `resize` | `"none" \| "vertical" \| "both"` | — | Controls whether the user can resize the framed textarea. |
