diff --git a/src/components/TextArea.tsx b/src/components/TextArea.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..1a538f42132dec57d940482ee726d74fab90f75a
--- /dev/null
+++ b/src/components/TextArea.tsx
@@ -0,0 +1,54 @@
+import { Textarea } from "@nextui-org/react";
+import { TextInputProps } from "./TextInput";
+import { baseInputClassNames } from "./utils/baseComponents";
+
+interface TextAreaProps extends Omit<TextInputProps, OmittedTextInputProps> {
+  minRows?: number;
+  maxRows?: number;
+  disableAutosize?: boolean;
+}
+
+type OmittedTextInputProps = "isClearable";
+
+const TextArea = ({
+  isRequired = false,
+  isDisabled = false,
+  isReadOnly = false,
+  label = "",
+  minRows = 3,
+  maxRows = 8,
+  maxLength,
+  value,
+  onValueChange,
+  isInvalid = false,
+  errorMessage,
+  disableAutosize = false,
+}: TextAreaProps) => {
+  const hasClearButton = false;
+  const hasMainWrapper = false;
+
+  return (
+    <Textarea
+      isRequired={isRequired}
+      isDisabled={isDisabled}
+      isReadOnly={isReadOnly}
+      label={label}
+      minRows={minRows}
+      maxRows={maxRows}
+      maxLength={maxLength}
+      value={value}
+      onValueChange={onValueChange}
+      isInvalid={isInvalid}
+      errorMessage={errorMessage}
+      disableAutosize={disableAutosize}
+      labelPlacement="outside"
+      variant="bordered"
+      classNames={{
+        ...baseInputClassNames(isDisabled, hasMainWrapper, hasClearButton),
+        input: disableAutosize && "resize-y",
+      }}
+    ></Textarea>
+  );
+};
+
+export default TextArea;
diff --git a/src/components/TextInput.tsx b/src/components/TextInput.tsx
index faa164b8f7f7fd197d3236f97fe3bf13b195c26a..14cec5527f615360759a96cfad73edc138ecbe96 100644
--- a/src/components/TextInput.tsx
+++ b/src/components/TextInput.tsx
@@ -68,3 +68,4 @@ const TextInput = ({
 };
 
 export default TextInput;
+export type { TextInputProps };
diff --git a/src/components/utils/baseComponents.tsx b/src/components/utils/baseComponents.tsx
index 3551dbc17a3429a0e6e53c41af06b19e6d848348..42dda5b59020f051a811b07e55fb5c4d50a5776f 100644
--- a/src/components/utils/baseComponents.tsx
+++ b/src/components/utils/baseComponents.tsx
@@ -42,7 +42,9 @@ type BaseInputProps = {
 type baseInputClassNamesObj = { [key in InputSlots]: string };
 
 export const baseInputClassNames = (
-  isDisabled: boolean
+  isDisabled: boolean,
+  hasMainWrapper: boolean = true, // for some components (i.e., textarea) the inputwrapper is the main wrapper,
+  hasClearButton: boolean = true
 ): baseInputClassNamesObj => {
   // this is the border color (use text-*)
   const mainWrapperClass = (isDisabled: boolean) =>
@@ -64,9 +66,13 @@ export const baseInputClassNames = (
     base: cursorPointer(isDisabled),
     label: "!text-foreground-body",
     input: "!text-foreground-body bg-default",
-    inputWrapper: clsx("px-2 rounded-[4px]", formFieldBg(isDisabled)),
-    mainWrapper: mainWrapperClass(isDisabled),
-    clearButton: clearButtonClass(isDisabled),
+    inputWrapper: clsx(
+      "px-2 rounded-[4px]",
+      formFieldBg(isDisabled),
+      !hasMainWrapper && mainWrapperClass(isDisabled)
+    ),
+    mainWrapper: hasMainWrapper && mainWrapperClass(isDisabled),
+    clearButton: hasClearButton && clearButtonClass(isDisabled),
   } as baseInputClassNamesObj;
 };
 
diff --git a/src/index.ts b/src/index.ts
index e7ea8b04764cf2fbeaa01b43646f2ee39dd2e918..5bcf613893aa80f072c055b200db36164169839b 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -12,6 +12,7 @@ export { default as ProgressBar } from "./components/ProgressBar";
 export { default as Radio } from "./components/Radio";
 export { default as Slider } from "./components/Slider";
 export { default as Table } from "./components/Table";
+export { default as TextArea } from "./components/TextArea";
 export { default as TextInput } from "./components/TextInput";
 export { default as Toggle } from "./components/Toggle";
 export { default as Typography } from "./components/Typography";
diff --git a/src/stories/TextArea.stories.tsx b/src/stories/TextArea.stories.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..5213320b92056406651e6ed9b7c30fbd21070be0
--- /dev/null
+++ b/src/stories/TextArea.stories.tsx
@@ -0,0 +1,122 @@
+import { Meta } from "@storybook/react";
+import { useMemo, useState } from "react";
+import TextArea from "src/components/TextArea.tsx";
+
+const meta = {
+  title: "Components/Text Area",
+  component: TextArea,
+} satisfies Meta;
+
+export default meta;
+
+export const Default = () => {
+  const [value, setValue] = useState("");
+  return (
+    <TextArea
+      label="Some long story goes here."
+      value={value}
+      onValueChange={setValue}
+    ></TextArea>
+  );
+};
+
+export const CustomValidation = () => {
+  const [value, setValue] = useState("");
+
+  const validateOnlyCapitals = (str: string) => str.match(/^[A-Z]+/g);
+
+  const isInvalid = useMemo(() => {
+    if (value === "") return false;
+    return !validateOnlyCapitals(value);
+  }, [value]);
+
+  return (
+    <TextArea
+      label="Only capitals"
+      value={value}
+      onValueChange={setValue}
+      isInvalid={isInvalid}
+      errorMessage={isInvalid ? "Only capitals are allowed!" : ""}
+    />
+  );
+};
+
+export const Required = () => {
+  const [value, setValue] = useState("");
+  return (
+    <TextArea
+      label="I require a value"
+      isRequired={true}
+      value={value}
+      onValueChange={setValue}
+    />
+  );
+};
+
+export const Disabled = () => {
+  return (
+    <TextArea
+      label="You can't interact with this component!"
+      isDisabled={true}
+      value="*Evil laughter*"
+    />
+  );
+};
+
+export const ReadOnly = () => {
+  return (
+    <TextArea
+      label="You can't change this value!"
+      isReadOnly={true}
+      value="*Neutral laughter*"
+    />
+  );
+};
+
+export const MaxLength = () => {
+  const [value, setValue] = useState("");
+  return (
+    <TextArea
+      label="Maximum of 100 characters"
+      maxLength={100}
+      value={value}
+      onValueChange={setValue}
+    />
+  );
+};
+
+export const MaxRows = () => {
+  const [value, setValue] = useState("");
+  return (
+    <TextArea
+      label="Maximum of 2 rows"
+      maxRows={2}
+      value={value}
+      onValueChange={setValue}
+    />
+  );
+};
+
+export const MinRows = () => {
+  const [value, setValue] = useState("");
+  return (
+    <TextArea
+      label="Minimum of 3 rows"
+      maxRows={3}
+      value={value}
+      onValueChange={setValue}
+    />
+  );
+};
+
+export const DisableAutoSize = () => {
+  const [value, setValue] = useState("");
+  return (
+    <TextArea
+      label="Autosize is disabled"
+      disableAutosize={true}
+      value={value}
+      onValueChange={setValue}
+    />
+  );
+};
\ No newline at end of file