diff --git a/.changeset/text-area-auto-resize.md b/.changeset/text-area-auto-resize.md
new file mode 100644
index 0000000..60920ba
--- /dev/null
+++ b/.changeset/text-area-auto-resize.md
@@ -0,0 +1,5 @@
+---
+"@makeplane/propel": minor
+---
+
+Add `autoResize` (and optional `maxRows`) to `TextArea` and `TextAreaField` so the control grows with its value.
diff --git a/apps/docs/src/demos/text-area-field/auto-resize.tsx b/apps/docs/src/demos/text-area-field/auto-resize.tsx
new file mode 100644
index 0000000..0d3d447
--- /dev/null
+++ b/apps/docs/src/demos/text-area-field/auto-resize.tsx
@@ -0,0 +1,14 @@
+import { TextAreaField } from "@makeplane/propel/components/text-area-field";
+
+export default function AutoResizeDemo() {
+ return (
+
+ );
+}
diff --git a/apps/docs/src/demos/text-area/auto-resize.tsx b/apps/docs/src/demos/text-area/auto-resize.tsx
new file mode 100644
index 0000000..5edf50f
--- /dev/null
+++ b/apps/docs/src/demos/text-area/auto-resize.tsx
@@ -0,0 +1,17 @@
+import { TextArea, TextAreaGroup } from "@makeplane/propel/components/text-area";
+
+export default function AutoResizeDemo() {
+ return (
+
+
+
+ );
+}
diff --git a/apps/docs/src/pages/components/text-area-field.mdx b/apps/docs/src/pages/components/text-area-field.mdx
index 65281ca..9eeb1d5 100644
--- a/apps/docs/src/pages/components/text-area-field.mdx
+++ b/apps/docs/src/pages/components/text-area-field.mdx
@@ -15,6 +15,8 @@ import InvalidDemo from "~/demos/text-area-field/invalid.tsx";
import invalidSource from "~/demos/text-area-field/invalid.tsx?raw";
import ResizeDemo from "~/demos/text-area-field/resize.tsx";
import resizeSource from "~/demos/text-area-field/resize.tsx?raw";
+import AutoResizeDemo from "~/demos/text-area-field/auto-resize.tsx";
+import autoResizeSource from "~/demos/text-area-field/auto-resize.tsx?raw";
import SizesDemo from "~/demos/text-area-field/sizes.tsx";
import sizesSource from "~/demos/text-area-field/sizes.tsx?raw";
@@ -72,6 +74,15 @@ The `resize` prop controls the native drag handle: `vertical` allows height chan
+### Auto resize
+
+`autoResize` grows the field with its value (size min-height as the floor) and turns the native
+resize handle off. `maxRows` caps the visible lines; further content scrolls.
+
+
+
+
+
### Invalid
Setting `error` overrides `hint`, marks the field invalid (`aria-invalid`), and recolors the border to danger.
diff --git a/apps/docs/src/pages/components/text-area.mdx b/apps/docs/src/pages/components/text-area.mdx
index e611009..0e676af 100644
--- a/apps/docs/src/pages/components/text-area.mdx
+++ b/apps/docs/src/pages/components/text-area.mdx
@@ -11,6 +11,8 @@ import BasicDemo from "~/demos/text-area/basic.tsx";
import basicSource from "~/demos/text-area/basic.tsx?raw";
import ResizeDemo from "~/demos/text-area/resize.tsx";
import resizeSource from "~/demos/text-area/resize.tsx?raw";
+import AutoResizeDemo from "~/demos/text-area/auto-resize.tsx";
+import autoResizeSource from "~/demos/text-area/auto-resize.tsx?raw";
import SizesDemo from "~/demos/text-area/sizes.tsx";
import sizesSource from "~/demos/text-area/sizes.tsx?raw";
import SurfacesDemo from "~/demos/text-area/surfaces.tsx";
@@ -85,6 +87,16 @@ axes. The leaf itself is never resizable.
+### 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.
+
+
+
+
+
### With description
diff --git a/packages/propel/src/components/text-area-field/text-area-field.stories.tsx b/packages/propel/src/components/text-area-field/text-area-field.stories.tsx
index 1625226..74ac214 100644
--- a/packages/propel/src/components/text-area-field/text-area-field.stories.tsx
+++ b/packages/propel/src/components/text-area-field/text-area-field.stories.tsx
@@ -110,6 +110,46 @@ export const Scroll: Story = {
),
};
+/**
+ * `autoResize` grows the field with its value and turns the native resize handle off. `maxRows`
+ * caps the visible lines; further content scrolls.
+ */
+export const AutoResize: Story = {
+ args: {
+ label: "Comment",
+ autoResize: true,
+ maxRows: 6,
+ rows: 2,
+ placeholder: "Type to grow the field…",
+ },
+ render: (args) => (
+
+
+
+ ),
+};
+
+/**
+ * Interaction test: typing additional lines grows a `TextAreaField` past its initial height, and
+ * the wrapping group stays `resize: none`.
+ */
+export const AutoResizeGrowsWithContent: Story = {
+ ...AutoResize,
+ tags: ["!dev", "!autodocs", "!manifest"],
+ play: async ({ canvas, userEvent }) => {
+ const textarea = canvas.getByRole("textbox", { name: "Comment" });
+ const group = textarea.parentElement;
+ if (group == null) throw new Error("expected a TextAreaGroup wrapper");
+ await expect(getComputedStyle(group).resize).toBe("none");
+ const initial = textarea.getBoundingClientRect().height;
+ await userEvent.type(
+ textarea,
+ "one{Enter}two{Enter}three{Enter}four{Enter}five{Enter}six{Enter}seven",
+ );
+ await expect(textarea.getBoundingClientRect().height).toBeGreaterThan(initial);
+ },
+};
+
/** The error treatment: danger border, danger helper text, and `aria-invalid`. */
export const Invalid: Story = {
args: {
diff --git a/packages/propel/src/components/text-area-field/text-area-field.tsx b/packages/propel/src/components/text-area-field/text-area-field.tsx
index 6ff2e81..94a6f94 100644
--- a/packages/propel/src/components/text-area-field/text-area-field.tsx
+++ b/packages/propel/src/components/text-area-field/text-area-field.tsx
@@ -14,11 +14,24 @@ export type TextAreaFieldProps = Omit & {
/** Size scale. `lg` | `xl` | `2xl`. */
size: InputSize;
/**
- * Native resize handle on the bordered frame.
+ * Native resize handle on the bordered frame. Forced to `none` when `autoResize` is set, so the
+ * drag handle does not fight content-driven height.
*
* @default "vertical"
*/
resize?: TextAreaResize;
+ /**
+ * Grow the control with its value, using the size min-height as the floor. Disables the native
+ * resize handle.
+ *
+ * @default false
+ */
+ autoResize?: boolean;
+ /**
+ * Maximum visible lines when `autoResize` is set. Further lines scroll inside the control.
+ * Unbounded when omitted.
+ */
+ maxRows?: number;
/** Label text shown above the control. */
label?: string;
/** Marks the field required: adds a `*` asterisk and sets `required`. */
@@ -36,7 +49,8 @@ export type TextAreaFieldProps = Omit & {
/**
* Multi-line text field built on Base UI `Field`, rendering the control as a `