Repository: AxaFrance/design-system
Pull request #1105: feat(apollo,look&feel): ajout du composant Textarea
Author: login: neehal-axa
Labels: name: component
description: component needs to be worked on
name: css-package
description: Affects the CSS package
name: theme-client
description: Changes relatives to the client theme
name: theme-rospect
description: Changes relatives to the Propect theme
name: Organisme
Created: 2025-04-08T09:27:57Z | Merged: 2025-04-14T14:10:17Z

Lien du issue : https://github.com/AxaFrance/design-system/issues/835


Diff:
diff --git a/apps/apollo-stories/src/components/TextArea/TextArea.mdx b/apps/apollo-stories/src/components/TextArea/TextArea.mdx
new file mode 100644
index 0000000000..445fc883a9
--- /dev/null
+++ b/apps/apollo-stories/src/components/TextArea/TextArea.mdx
@@ -0,0 +1,29 @@
+import { Canvas, Controls, Meta } from "@storybook/addon-docs";
+import * as TextAreaStories from "./TextArea.stories";
+
+<Meta of={TextAreaStories} name="TextArea" />
+
+# TextArea
+
+To use the TextArea import it like that:
+
+```tsx
+import { TextArea } from "@axa-fr/design-system-apollo-react";
+
+const MyComponent = () => (
+  <TextArea
+    ItemLabelComponent={}
+    ItemMessageComponent={}
+    label={}
+    sideButtonLabel={}
+  />
+);
+```
+
+## Default
+
+<Canvas of={TextAreaStories.TextAreaStory} />
+
+## Playground
+
+<Controls of={TextAreaStories.TextAreaStory} />
diff --git a/apps/look-and-feel-stories/src/TextArea.stories.tsx b/apps/apollo-stories/src/components/TextArea/TextArea.stories.tsx
similarity index 78%
rename from apps/look-and-feel-stories/src/TextArea.stories.tsx
rename to apps/apollo-stories/src/components/TextArea/TextArea.stories.tsx
index 26c00cd819..8bbddc73de 100644
--- a/apps/look-and-feel-stories/src/TextArea.stories.tsx
+++ b/apps/apollo-stories/src/components/TextArea/TextArea.stories.tsx
@@ -1,14 +1,15 @@
-import { TextArea } from "@axa-fr/design-system-look-and-feel-react";
+import { TextArea } from "@axa-fr/design-system-apollo-react";
 import type { Meta, StoryObj } from "@storybook/react";
+import React from "react";
 
 const meta: Meta<typeof TextArea> = {
   component: TextArea,
   title: "Components/Form/Input/TextArea",
   args: {
-    value: "Lorem ipsum",
+    value: "Placeholder",
     label: "Label",
     placeholder: "Placeholder",
-    helper: "Informations complémentaires",
+    helper: "1800 caractères maximum.",
     name: "name",
     id: "nameid",
     disabled: false,
@@ -45,6 +46,14 @@ export const TextAreaWithDescriptionStory: Story = {
   },
 };
 
+export const TextAreaWithButton: Story = {
+  name: "TextArea with button",
+  render,
+  args: {
+    buttonLabel: "En savoir plus",
+  },
+};
+
 export const TextAreaOnErrorStory: Story = {
   name: "TextArea on error",
   render,
@@ -55,10 +64,11 @@ export const TextAreaOnErrorStory: Story = {
   },
 };
 
-export const TextAreaWithButton: Story = {
-  name: "TextArea with button",
+export const TextAreaDisabled: Story = {
+  name: "TextArea disabled",
   render,
   args: {
     buttonLabel: "En savoir plus",
+    disabled: true,
   },
 };
diff --git a/apps/look-and-feel-stories-css/src/TextArea.stories.ts b/apps/look-and-feel-stories-css/src/TextArea.stories.ts
deleted file mode 100644
index 7cc559c664..0000000000
--- a/apps/look-and-feel-stories-css/src/TextArea.stories.ts
+++ /dev/null
@@ -1,170 +0,0 @@
-import "@axa-fr/design-system-apollo-css/dist/Button/ButtonLF.scss";
-import "@axa-fr/design-system-look-and-feel-css/dist/Form/InputError/InputError.scss";
-import "@axa-fr/design-system-look-and-feel-css/dist/Form/TextArea/TextArea.scss";
-import type { Args, Meta, StoryObj } from "@storybook/html";
-
-const meta: Meta = {
-  args: {
-    value: "Lorem ipsum",
-    label: "Label",
-    placeholder: "Your name",
-    disabled: false,
-    required: true,
-    isOnError: false,
-  },
-  argTypes: {
-    label: {
-      control: { type: "text" },
-    },
-  },
-  title: "Components/Form/Input/TextArea",
-};
-
-export default meta;
-
-const getContainer = () => {
-  const container = document.createElement("div");
-  container.className = "af-form__input-container";
-
-  return container;
-};
-
-const getTextArea = (args: Args) => {
-  const input = document.createElement("textarea");
-  input.id = "nameid";
-  input.name = "name";
-  input.className = "af-form__input-textarea";
-  if (args.isOnError) input.className += " af-form__input-textarea--error";
-  input.placeholder = args.placeholder;
-  input.value = args.value;
-  input.disabled = args.disabled;
-  input.required = args.required;
-
-  return input;
-};
-
-const getLabel = (args: Args) => {
-  const label = document.createElement("label");
-  label.htmlFor = "nameid";
-  label.className = "af-form__input-label";
-  label.textContent = args.label;
-
-  if (args.required) {
-    const required = document.createElement("span");
-    required.textContent = " *";
-    label.appendChild(required);
-  }
-
-  return label;
-};
-
-const getDescription = (args: Args) => {
-  const description = document.createElement("span");
-  description.className = "af-form__input-description";
-  description.textContent = args.description;
-
-  return description;
-};
-
-const getError = (args: Args) => {
-  const alert = document.createElement("div");
-  alert.className = `af-input-error`;
-  alert.innerHTML = `
-        <svg class="af-input-error__icon" focusable="false" aria-hidden="true" viewBox="0 0 24 24" data-testid="ErrorOutlineIcon"><path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2M12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8"></path></svg>
-        ${
-          args.title &&
-          `<span class="af-input-error__message">${args.title}</span>`
-        }
-    `;
-
-  return alert;
-};
-
-const getKnowMore = () => {
-  const knowMore = document.createElement("button");
-  knowMore.className = "af-btn-client af-btn-client--ghost af-form__input-more";
-  knowMore.innerHTML = `<svg focusable="false" aria-hidden="true" viewBox="0 -960 960 960">
-    <path d="M453-280h60v-240h-60v240Zm26.98-314q14.02 0 23.52-9.2T513-626q0-14.45-9.48-24.22-9.48-9.78-23.5-9.78t-23.52 9.78Q447-640.45 447-626q0 13.6 9.48 22.8 9.48 9.2 23.5 9.2Zm.29 514q-82.74 0-155.5-31.5Q252-143 197.5-197.5t-86-127.34Q80-397.68 80-480.5t31.5-155.66Q143-709 197.5-763t127.34-85.5Q397.68-880 480.5-880t155.66 31.5Q709-817 763-763t85.5 127Q880-563 880-480.27q0 82.74-31.5 155.5Q817-252 763-197.68q-54 54.31-127 86Q563-80 480.27-80Zm.23-60Q622-140 721-239.5t99-241Q820-622 721.19-721T480-820q-141 0-240.5 98.81T140-480q0 141 99.5 240.5t241 99.5Zm-.5-340Z"></path>
-  </svg>
-  En savoir plus`;
-
-  return knowMore;
-};
-
-export const TextAreaStory: StoryObj = {
-  name: "TextArea",
-  render: (args) => {
-    const container = getContainer();
-    const input = getTextArea(args);
-    const label = getLabel(args);
-
-    container.appendChild(label);
-    container.appendChild(input);
-
-    return container;
-  },
-};
-
-export const TextAreaWithDescriptionStory: StoryObj = {
-  name: "TextArea with description",
-  render: (args) => {
-    const container = getContainer();
-    const input = getTextArea(args);
-    const label = getLabel(args);
-    const description = getDescription(args);
-
-    container.appendChild(label);
-    container.appendChild(description);
-    container.appendChild(input);
-
-    return container;
-  },
-  args: {
-    description: "Description",
-  },
-};
-
-export const TextAreaOnErrorStory: StoryObj = {
-  name: "TextArea on error",
-  render: (args) => {
-    const container = getContainer();
-    const input = getTextArea(args);
-    const label = getLabel(args);
-
-    const description = getDescription(args);
-    const error = getError(args);
-
-    container.appendChild(label);
-    container.appendChild(description);
-    container.appendChild(input);
-    container.appendChild(error);
-
-    return container;
-  },
-  args: {
-    isOnError: true,
-    description: "Description",
-    title: "Error Message",
-  },
-};
-
-export const TextAreaWithKnowMore: StoryObj = {
-  name: "TextArea with know more",
-  render: (args) => {
-    const container = getContainer();
-    const input = getTextArea(args);
-    const label = getLabel(args);
-    const description = getDescription(args);
-    const knowMore = getKnowMore();
-
-    container.appendChild(label);
-    container.appendChild(description);
-    container.appendChild(knowMore);
-    container.appendChild(input);
-
-    return container;
-  },
-  args: {
-    description: "Description",
-  },
-};
diff --git a/apps/look-and-feel-stories/src/Textarea/TextArea.mdx b/apps/look-and-feel-stories/src/Textarea/TextArea.mdx
new file mode 100644
index 0000000000..d925f30ef1
--- /dev/null
+++ b/apps/look-and-feel-stories/src/Textarea/TextArea.mdx
@@ -0,0 +1,22 @@
+import { Canvas, Controls, Meta } from "@storybook/addon-docs";
+import * as TextAreaStories from "./TextArea.stories";
+
+<Meta of={TextAreaStories} name="TextArea" />
+
+# TextArea
+
+To use the TextArea import it like that:
+
+```tsx
+import { TextArea } from "@axa-fr/design-system-look-and-feel-react";
+
+const MyComponent = () => <TextArea />;
+```
+
+## Default
+
+<Canvas of={TextAreaStories.TextAreaStory} />
+
+## Playground
+
+<Controls of={TextAreaStories.TextAreaStory} />
diff --git a/apps/look-and-feel-stories/src/Textarea/TextArea.stories.tsx b/apps/look-and-feel-stories/src/Textarea/TextArea.stories.tsx
new file mode 100644
index 0000000000..df199a42e6
--- /dev/null
+++ b/apps/look-and-feel-stories/src/Textarea/TextArea.stories.tsx
@@ -0,0 +1,83 @@
+import { TextArea } from "@axa-fr/design-system-look-and-feel-react";
+import type { Meta, StoryObj } from "@storybook/react";
+
+const meta: Meta<typeof TextArea> = {
+  component: TextArea,
+  title: "Components/Form/Input/TextArea",
+  args: {
+    value: "Lorem ipsum",
+    label: "Label",
+    placeholder: "Placeholder",
+    helper: "Informations complémentaires",
+    name: "name",
+    id: "nameid",
+    disabled: false,
+    required: false,
+    className: "",
+    buttonLabel: "",
+  },
+  argTypes: {
+    onChange: { action: "onChange" },
+  },
+};
+
+export default meta;
+
+type Story = StoryObj<typeof TextArea>;
+
+const render = ({
+  onChange,
+  ...args
+}: React.ComponentProps<typeof TextArea>) => (
+  <TextArea onChange={onChange} {...args} />
+);
+
+export const TextAreaStory: Story = {
+  name: "TextArea",
+  render,
+};
+
+export const TextAreaWithDescriptionStory: Story = {
+  name: "TextArea with description",
+  render,
+  args: {
+    description: "Description",
+  },
+};
+
+export const TextAreaOnErrorStory: Story = {
+  name: "TextArea on error",
+  render,
+  args: {
+    classModifier: "error",
+    description: "Description",
+    error: "Error Message",
+  },
+};
+
+export const TextAreaWithButton: Story = {
+  name: "TextArea with button",
+  render,
+  args: {
+    buttonLabel: "En savoir plus",
+    disabled: false,
+  },
+};
+
+export const TextAreaDisabled: Story = {
+  args: {
+    value: "Placeholder",
+    label: "Label",
+    placeholder: "Placeholder",
+    helper: "Informations complémentaires",
+    name: "name",
+    id: "nameid",
+    disabled: true,
+    required: false,
+    className: "",
+    buttonLabel: "En savoir plus",
+  },
+
+  name: "TextArea disabled",
+  render,
+};
diff --git a/client/apollo/css/src/Form/TextArea/TextAreaApollo.scss b/client/apollo/css/src/Form/TextArea/TextAreaApollo.scss
new file mode 100644
index 0000000000..0a534a0a0b
--- /dev/null
+++ b/client/apollo/css/src/Form/TextArea/TextAreaApollo.scss
@@ -0,0 +1,25 @@
+@use "TextAreaCommon";
+
+.af-form__input-textarea {
+  --input-text-area-border-radius: var(--radius-8);
+  --input-text-area-border-color: var(--axa-blue-65);
+  --input-text-area-height: 148px;
+  --input-text-area-background: var(--white);
+  --input-text-area-color: var(--neutral-80);
+
+  &--error {
+    --input-text-area-border-color: var(--axa-red-100);
+  }
+
+  &:disabled {
+    --input-text-area-border-color: var(--neutral-14);
+    --input-text-area-background: var(--neutral-5);
+  }
+
+  &:not(:disabled, &--error) {
+    &:focus,
+    &:hover {
+      --input-text-area-border-color: var(--axa-blue-100);
+    }
+  }
+}
diff --git a/client/apollo/css/src/Form/TextArea/TextAreaCommon.scss b/client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
new file mode 100644
index 0000000000..8a560bc36d
--- /dev/null
+++ b/client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
@@ -0,0 +1,48 @@
+@use "../../common/breakpoints" as breakpoints;
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(--input-text-area-height / var(--font-size-base) * 1rem);
+  padding: 16px;
+  border: 1px solid var(--input-text-area-border-color);
+  border-radius: var(--input-text-area-border-radius);
+  font: var(--font-family-base);
+  font-size: calc(16 / var(--font-size-base) * 1rem);
+  line-height: calc(20 / var(--font-size-base) * 1rem);
+  color: var(--input-text-area-color);
+  background-color: var(--input-text-area-background);
+  box-shadow: 0 0 0 1px var(--input-text-area-background);
+
+  @media (width > #{breakpoints.$breakpoint-md}) {
+    width: 100%;
+    font-size: calc(18 / var(--font-size-base) * 1rem);
+    line-height: calc(24 / var(--font-size-base) * 1rem);
+  }
+
+  &--error {
+    border: 1px solid var(--input-text-area-border-color);
+    box-shadow: 1px solid var(--input-text-area-border-color);
+    outline: none;
+  }
+
+  &:enabled,
+  &:focus,
+  &:active {
+    box-shadow: 0 0 0 1px var(--white);
+    outline: none;
+  }
+
+  &:disabled {
+    border: 1px solid var(--input-text-area-border-color);
+    background: var(--input-text-area-background);
+    pointer-events: none;
+  }
+
+  &:not(:disabled, &--error) {
+    &:focus,
+    &:hover {
+      border: 1px solid var(--input-text-area-border-color);
+      box-shadow: 0 0 0 1px var(--input-text-area-border-color);
+    }
+  }
+}
diff --git a/client/apollo/css/src/Form/TextArea/TextAreaLF.scss b/client/apollo/css/src/Form/TextArea/TextAreaLF.scss
new file mode 100644
index 0000000000..7cbbabe981
--- /dev/null
+++ b/client/apollo/css/src/Form/TextArea/TextAreaLF.scss
@@ -0,0 +1,25 @@
+@use "TextAreaCommon";
+
+.af-form__input-textarea {
+  --input-text-area-height: 142px;
+  --input-text-area-border-radius: var(--default-border-radius);
+  --input-text-area-border-color: var(--color-gray-700);
+  --input-text-area-background: var(--color-white);
+  --input-text-area-color: var(--color-gray);
+
+  &--error {
+    --input-text-area-border-color: var(--color-red-700);
+  }
+
+  &:disabled {
+    --input-text-area-border-color: var(--color-gray-400);
+    --input-text-area-background: var(--color-gray-200);
+  }
+
+  &:not(:disabled, &--error) {
+    &:focus,
+    &:hover {
+      --input-text-area-border-color: var(--color-axa);
+    }
+  }
+}
diff --git a/client/apollo/css/src/apollo.scss b/client/apollo/css/src/apollo.scss
index 3d49d95105..f8d67a354f 100644
--- a/client/apollo/css/src/apollo.scss
+++ b/client/apollo/css/src/apollo.scss
@@ -5,6 +5,7 @@
 @use "./Form/ItemMessage/ItemMessageApollo";
 @use "./Form/ItemLabel/ItemLabelApollo";
 @use "./Form/TextInput/TextInputApollo";
+@use "./Form/TextArea/TextAreaApollo";
 @use "./Icon/IconApollo";
 @use "./Divider/DividerApollo";
 @use "./Link/LinkApollo";
diff --git a/client/apollo/css/src/look-and-feel.scss b/client/apollo/css/src/look-and-feel.scss
index 793766ec0c..1058109c06 100644
--- a/client/apollo/css/src/look-and-feel.scss
+++ b/client/apollo/css/src/look-and-feel.scss
@@ -5,6 +5,7 @@
 @use "./Form/ItemMessage/ItemMessageLF";
 @use "./Form/ItemLabel/ItemLabelLF";
 @use "./Form/TextInput/TextInputLF";
+@use "./Form/TextArea/TextAreaLF";
 @use "./Icon/IconLF";
 @use "./Divider/DividerLF";
 @use "./Link/LinkLF";
diff --git a/client/apollo/react/src/Form/TextArea/TextAreaApollo.tsx b/client/apollo/react/src/Form/TextArea/TextAreaApollo.tsx
new file mode 100644
index 0000000000..f6da517333
--- /dev/null
+++ b/client/apollo/react/src/Form/TextArea/TextAreaApollo.tsx
@@ -0,0 +1,18 @@
+import "@axa-fr/design-system-apollo-css/dist/Form/TextArea/TextAreaApollo.scss";
+import type { ComponentProps } from "react";
+import { ItemLabel } from "../ItemLabel/ItemLabelApollo";
+import { ItemMessage } from "../ItemMessage/ItemMessageApollo";
+import { TextArea as TextAreaCommon } from "./TextAreaCommon";
+
+export const TextArea = (
+  props: Omit<
+    ComponentProps<typeof TextAreaCommon>,
+    "ItemLabelComponent" | "ItemMessageComponent"
+  >,
+) => (
+  <TextAreaCommon
+    {...props}
+    ItemLabelComponent={ItemLabel}
+    ItemMessageComponent={ItemMessage}
+  />
+);
diff --git a/client/apollo/react/src/Form/TextArea/TextAreaCommon.tsx b/client/apollo/react/src/Form/TextArea/TextAreaCommon.tsx
new file mode 100644
index 0000000000..2c4d31fc2e
--- /dev/null
+++ b/client/apollo/react/src/Form/TextArea/TextAreaCommon.tsx
@@ -0,0 +1,89 @@
+import {
+  type ComponentProps,
+  ComponentPropsWithRef,
+  type ComponentType,
+  forwardRef,
+  MouseEventHandler,
+  useId,
+} from "react";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { ItemLabel } from "../ItemLabel/ItemLabelCommon";
+import { ItemMessage } from "../ItemMessage/ItemMessageCommon";
+
+type Props = ComponentPropsWithRef<"textarea"> & {
+  classModifier?: string;
+  sideButtonLabel: string;
+  onSideButtonClick?: MouseEventHandler<HTMLButtonElement>;
+  helper?: string;
+  error?: string;
+  description?: string;
+  label: ComponentProps<typeof ItemLabel>["label"];
+  ItemLabelComponent: ComponentType<
+    Omit<ComponentProps<typeof ItemLabel>, "ButtonComponent">
+  >;
+  ItemMessageComponent: ComponentType<ComponentProps<typeof ItemMessage>>;
+  buttonLabel?: string;
+  onButtonClick?: MouseEventHandler<HTMLButtonElement>;
+} & Partial<ComponentPropsWithRef<typeof ItemMessage>>;
+
+const TextArea = forwardRef<HTMLTextAreaElement, Props>(
+  (
+    {
+      className,
+      classModifier = "",
+      label,
+      description,
+      helper,
+      error,
+      buttonLabel,
+      onButtonClick,
+      required,
+      sideButtonLabel,
+      ItemLabelComponent,
+      ItemMessageComponent,
+      onSideButtonClick,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const componentClassName = getComponentClassName(
+      "af-form__input-textarea",
+      className,
+      classModifier,
+    );
+
+    let inputId = useId();
+    inputId = otherProps.id || inputId;
+    const idError = useId();
+    const idLabel = useId();
+
+    return (
+      <div className="af-form__input-container">
+        <ItemLabelComponent
+          label={label}
+          description={description}
+          buttonLabel={buttonLabel}
+          onButtonClick={onButtonClick}
+          sideButtonLabel={sideButtonLabel}
+          onSideButtonClick={onSideButtonClick}
+          required={required}
+          inputId={inputId}
+          idLabel={idLabel}
+        />
+        <textarea
+          id={inputId}
+          className={componentClassName}
+          ref={inputRef}
+          aria-errormessage={idError}
+          aria-invalid={Boolean(error)}
+          {...otherProps}
+        />
+        {helper && <span className="af-form__input-helper">{helper}</span>}
+        <ItemMessageComponent id={idError} message={error} />
+      </div>
+    );
+  },
+);
+TextArea.displayName = "TextArea";
+
+export { TextArea };
diff --git a/client/apollo/react/src/Form/TextArea/TextAreaLF.tsx b/client/apollo/react/src/Form/TextArea/TextAreaLF.tsx
new file mode 100644
index 0000000000..bc5ca99bc8
--- /dev/null
+++ b/client/apollo/react/src/Form/TextArea/TextAreaLF.tsx
@@ -0,0 +1,18 @@
+import "@axa-fr/design-system-apollo-css/dist/Form/TextArea/TextAreaLF.scss";
+import type { ComponentProps } from "react";
+import { ItemLabel } from "../ItemLabel/ItemLabelLF";
+import { ItemMessage } from "../ItemMessage/ItemMessageLF";
+import { TextArea as TextAreaCommon } from "./TextAreaCommon";
+
+export const TextArea = (
+  props: Omit<
+    ComponentProps<typeof TextAreaCommon>,
+    "ItemLabelComponent" | "ItemMessageComponent"
+  >,
+) => (
+  <TextAreaCommon
+    {...props}
+    ItemLabelComponent={ItemLabel}
+    ItemMessageComponent={ItemMessage}
+  />
+);
diff --git a/client/apollo/react/src/Form/TextArea/__tests__/TextArea.test.tsx b/client/apollo/react/src/Form/TextArea/__tests__/TextArea.test.tsx
new file mode 100644
index 0000000000..e46ec4d5a4
--- /dev/null
+++ b/client/apollo/react/src/Form/TextArea/__tests__/TextArea.test.tsx
@@ -0,0 +1,35 @@
+import { render, screen } from "@testing-library/react";
+import { axe } from "jest-axe";
+import { TextArea } from "../TextAreaLF";
+
+describe("<TextArea />", () => {
+  test("should render component with default props", () => {
+    render(
+      <TextArea
+        label="Label"
+        value="Lorem Ipsum"
+        description="Description"
+        helper="Helper"
+        buttonLabel="Button label"
+        onChange={() => {}}
+        error="Error message"
+        sideButtonLabel="button"
+      />,
+    );
+    const textLabel = screen.getByText("Label");
+    const textAreDescritpion = screen.getByText("Description");
+    const textArea = screen.getByText("Lorem Ipsum");
+    const input = screen.getByRole("textbox");
+    expect(input).toBeInTheDocument();
+    expect(textLabel).toBeInTheDocument();
+    expect(textAreDescritpion).toBeInTheDocument();
+    expect(textArea).toBeInTheDocument();
+  });
+
+  it("shouldn't have an accessibility violation <TextArea />", async () => {
+    const { container } = render(
+      <TextArea label="Label" sideButtonLabel="button" />,
+    );
+    expect(await axe(container)).toHaveNoViolations();
+  });
+});
diff --git a/client/apollo/react/src/index.ts b/client/apollo/react/src/index.ts
index f35569b804..4f6840ceea 100644
--- a/client/apollo/react/src/index.ts
+++ b/client/apollo/react/src/index.ts
@@ -19,6 +19,7 @@ export { Tag, type TagVariants, tagVariants } from "./Tag/TagApollo";
 export { DebugGrid } from "./Grid/DebugGrid";
 export { ItemMessage } from "./Form/ItemMessage/ItemMessageApollo";
 export { ItemLabel } from "./Form/ItemLabel/ItemLabelApollo";
+export { TextArea } from "./Form/TextArea/TextAreaApollo";
 export { TextInput } from "./Form/TextInput/TextInputApollo";
 export {
   Icon,
diff --git a/client/apollo/react/src/indexLF.ts b/client/apollo/react/src/indexLF.ts
index 2484fdb6b3..a4d3aac36f 100644
--- a/client/apollo/react/src/indexLF.ts
+++ b/client/apollo/react/src/indexLF.ts
@@ -14,6 +14,7 @@ export { Tag, type TagVariants, tagVariants } from "./Tag/TagLF";
 export { DebugGrid } from "./Grid/DebugGrid";
 export { ItemMessage } from "./Form/ItemMessage/ItemMessageLF";
 export { ItemLabel } from "./Form/ItemLabel/ItemLabelLF";
+export { TextArea } from "./Form/TextArea/TextAreaLF";
 export { TextInput } from "./Form/TextInput/TextInputLF";
 export {
   Icon,
diff --git a/client/look-and-feel/css/src/Form/TextArea/TextArea.scss b/client/look-and-feel/css/src/Form/TextArea/TextArea.scss
deleted file mode 100644
index 6a98e59780..0000000000
--- a/client/look-and-feel/css/src/Form/TextArea/TextArea.scss
+++ /dev/null
@@ -1,41 +0,0 @@
-@use "../../common/common" as common;
-
-.af-form__input-textarea {
-  width: 100%;
-  height: common.rem(142);
-  padding: 1rem 2.5rem 1rem 1rem;
-  border: 1px solid var(--color-gray);
-  border-radius: var(--default-border-radius);
-  font-size: common.rem(16);
-  line-height: common.rem(20);
-  color: var(--color-gray-900);
-  background-color: var(--color-white);
-
-  @media (width > #{common.$breakpoint-md}) {
-    font-size: common.rem(18);
-    line-height: common.rem(24);
-  }
-
-  &--error {
-    border: 1px solid var(--color-red-700);
-    box-shadow: 0 0 0 1px var(--color-red-700) inset;
-  }
-
-  &:not(:empty, :hover, :focus, :active, [class*="--error"]) {
-    border: 1px solid var(--color-axa);
-  }
-
-  &:enabled {
-    &:focus,
-    &:active {
-      border: 1px solid var(--color-axa);
-      outline: none;
-    }
-  }
-
-  &:not(:disabled, :focus, :active, &--error):hover {
-    border: 1px solid var(--color-axa);
-    box-shadow: 0 0 0 1px var(--color-axa) inset;
-    outline: none;
-  }
-}
diff --git a/client/look-and-feel/css/src/look-and-feel.scss b/client/look-and-feel/css/src/look-and-feel.scss
index b2d37a7a7a..d9663c8d38 100644
--- a/client/look-and-feel/css/src/look-and-feel.scss
+++ b/client/look-and-feel/css/src/look-and-feel.scss
@@ -10,7 +10,6 @@
 @use "Tabs/Tabs";
 @use "Form/Checkbox/Checkbox";
 @use "Form/Select/Select";
-@use "Form/TextArea/TextArea";
 @use "Form/FileUpload/FileUpload";
 @use "Modal/Modal";
 @use "Pagination/Pagination";
diff --git a/client/look-and-feel/react/src/Form/TextArea/TextArea.tsx b/client/look-and-feel/react/src/Form/TextArea/TextArea.tsx
index f35299c506..c92baac05a 100644
--- a/client/look-and-feel/react/src/Form/TextArea/TextArea.tsx
+++ b/client/look-and-feel/react/src/Form/TextArea/TextArea.tsx
@@ -1,87 +1,2 @@
-import {
-  ComponentPropsWithRef,
-  forwardRef,
-  MouseEventHandler,
-  useId,
-} from "react";
-import infoIcon from "@material-symbols/svg-400/outlined/info.svg";
-import { getComponentClassName } from "../../utilities";
-import { Button, Svg } from "../..";
-import { InputError } from "../InputError";
-
-type Props = ComponentPropsWithRef<"textarea"> & {
-  classModifier?: string;
-  helper?: string;
-  error?: string;
-  description?: string;
-  label?: string;
-  buttonLabel?: string;
-  onButtonClick?: MouseEventHandler<HTMLButtonElement>;
-};
-
-const TextArea = forwardRef<HTMLTextAreaElement, Props>(
-  (
-    {
-      className,
-      classModifier = "",
-      label,
-      description,
-      helper,
-      error,
-      buttonLabel,
-      onButtonClick,
-      required,
-      ...otherProps
-    },
-    inputRef,
-  ) => {
-    const componentClassName = getComponentClassName(
-      "af-form__input-textarea",
-      className,
-      classModifier,
-    );
-
-    let inputId = useId();
-    inputId = otherProps.id || inputId;
-    const idError = useId();
-
-    return (
-      <div className="af-form__input-container">
-        {label && (
-          <div className="af-form__label-container">
-            <label htmlFor={inputId} className="af-form__input-label">
-              {label} {required && <span> *</span>}
-            </label>
-            {description && (
-              <span className="af-form__input-description">{description}</span>
-            )}
-            {buttonLabel && (
-              <Button
-                className="af-form__input-more"
-                variant="ghost"
-                iconLeft={<Svg src={infoIcon} />}
-                onClick={onButtonClick}
-              >
-                {buttonLabel}
-              </Button>
-            )}
-          </div>
-        )}
-        <textarea
-          id={inputId}
-          className={componentClassName}
-          ref={inputRef}
-          aria-errormessage={idError}
-          aria-invalid={Boolean(error)}
-          {...otherProps}
-        />
-        {helper && <span className="af-form__input-helper">{helper}</span>}
-        {error && <InputError id={idError} message={error} />}
-      </div>
-    );
-  },
-);
-
-TextArea.displayName = "TextArea";
-
-export { TextArea };
+/* eslint-disable import/no-extraneous-dependencies */
+export { TextArea } from "@axa-fr/design-system-apollo-react/lf";
diff --git a/client/look-and-feel/react/src/Form/TextArea/__tests__/TextArea.test.tsx b/client/look-and-feel/react/src/Form/TextArea/__tests__/TextArea.test.tsx
deleted file mode 100644
index e5134b43e7..0000000000
--- a/client/look-and-feel/react/src/Form/TextArea/__tests__/TextArea.test.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { render, screen } from "@testing-library/react";
-import { TextArea } from "../TextArea";
-
-describe("<TextArea />", () => {
-  test("should render component with default props", () => {
-    render(
-      <TextArea
-        label="Label"
-        value="Lorem Ipsum"
-        description="Description"
-        helper="Helper"
-        buttonLabel="Button label"
-        error="Error message"
-      />,
-    );
-
-    screen.getByRole("textbox");
-    screen.getByText("Label");
-    screen.getByText("Lorem Ipsum");
-    screen.getByText("Description");
-    screen.getByText("Helper");
-    screen.getByRole("button", { name: "Button label" });
-    screen.getByText("Error message");
-  });
-
-  test("should render asterisk if required", () => {
-    render(<TextArea label="Required label" required />);
-
-    screen.getByText("Required label");
-    screen.getByText("*");
-  });
-});
diff --git a/client/look-and-feel/react/src/Form/TextArea/index.ts b/client/look-and-feel/react/src/Form/TextArea/index.ts
deleted file mode 100644
index 3d49d2aa38..0000000000
--- a/client/look-and-feel/react/src/Form/TextArea/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import "@axa-fr/design-system-look-and-feel-css/dist/Form/TextArea/TextArea.scss";
-
-export { TextArea } from "./TextArea";
diff --git a/client/look-and-feel/react/src/index.ts b/client/look-and-feel/react/src/index.ts
index e8137e7787..e713b1f290 100644
--- a/client/look-and-feel/react/src/index.ts
+++ b/client/look-and-feel/react/src/index.ts
@@ -21,7 +21,7 @@ export { ItemLabel } from "./Form/ItemLabel/ItemLabel";
 export { Radio, RadioSelect } from "./Form/Radio";
 export { Select } from "./Form/Select";
 export { TextInput } from "./Form/Text/Text";
-export { TextArea } from "./Form/TextArea";
+export { TextArea } from "./Form/TextArea/TextArea";
 export { DebugGrid } from "./Grid/DebugGrid";
 export { IconBg } from "./IconBg";
 export { Footer } from "./Layout/Footer/Footer";


Reviews:
user: login: pjbeaugendre
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T14:24:13Z
user: login: GuillaumeKESTEMAN
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T12:50:08Z
user: login: GuillaumeKESTEMAN
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:41:53Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:45:31Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:49:02Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:49:26Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:50:28Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:51:25Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:52:13Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:53:01Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:53:39Z
user: login: samuel-gomez-axa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T13:54:00Z
user: login: samuel-gomez-axa
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-10T13:34:38Z
user: login: GuillaumeKESTEMAN
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T08:08:05Z
user: login: GuillaumeKESTEMAN
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T12:10:04Z
user: login: samuel-gomez-axa
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T12:18:39Z
user: login: pjbeaugendre
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T12:32:21Z
user: login: samuel-gomez-axa
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T13:02:49Z
user: login: pjbeaugendre
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T14:09:14Z

Review comments:
diff_hunk: @@ -44,6 +45,7 @@
   --axa-red-digital-100: hsl(357deg, 100%, 63%);
   --red-alert-100: hsl(0deg, 100%, 45%);
   --red-alert-80: hsl(0deg, 100%, 56%);
+  --red-alert-43: hsl(350deg, 82%, 43%);
path: client/apollo/css/src/common/tokens.scss
user: login: pjbeaugendre
body: C'est une couleur LF, il ne faut pas mélanger les tokens
created_at: 2025-04-08T14:19:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +64,11 @@
   --neutral-25: hsl(from var(--black) h s 80%);
   --neutral-14: hsl(from var(--black) h s 90%);
   --neutral-5: hsl(from var(--black) h s 96%);
+  --axa-gray-20: hsl(0deg, 0%, 20%);
path: client/apollo/css/src/common/tokens.scss
user: login: pjbeaugendre
body: Si c'est des couleurs LF, à ne pas mettre dans ce fichier. Sinon les couleurs nécessaire pour Apollo existe déjà avec les neutral
https://www.figma.com/design/AhUJ7ZDUwSEaxD5pKaN3hq/Fondations-B2C?node-id=4-15829&p=f&t=WpqKlGoTpa0afET3-0
created_at: 2025-04-08T14:20:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+import {
+  ComponentPropsWithRef,
+  forwardRef,
+  MouseEventHandler,
+  useId,
+} from "react";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { Button } from "../../Button/ButtonCommon";
+import { ItemLabel } from "../ItemLabel/ItemLabelCommon";
+import { ItemMessage } from "../ItemMessage/ItemMessageCommon";
+
+type Props = ComponentPropsWithRef<"textarea"> & {
+  classModifier?: string;
+  sideButtonLabel: string;
+  onSideButtonClick?: MouseEventHandler<HTMLButtonElement>;
+  helper?: string;
+  error?: string;
+  description?: string;
+  label?: string;
+  buttonLabel?: string;
+  onButtonClick?: MouseEventHandler<HTMLButtonElement>;
+} & Partial<ComponentPropsWithRef<typeof ItemMessage>>;
+
+const TextArea = forwardRef<HTMLTextAreaElement, Props>(
+  (
+    {
+      className,
+      classModifier = "",
+      label,
+      description,
+      helper,
+      error,
+      buttonLabel,
+      onButtonClick,
+      required,
+      sideButtonLabel,
+      onSideButtonClick,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const componentClassName = getComponentClassName(
+      "af-form__input-textarea",
+      className,
+      classModifier,
+    );
+
+    let inputId = useId();
path: client/apollo/react/src/Form/TextArea/TextAreaCommon.tsx
user: login: pjbeaugendre
body: @samuel-gomez Je te mentionne car je ne sais pas si c'est forcément mieux

const inputId = otherProps.id ?? useId();
created_at: 2025-04-08T14:23:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,31 @@
+import { Canvas, Controls, Meta } from "@storybook/addon-docs";
+import * as TextAreaStories from "./TextArea.stories";
+
+<Meta of={TextAreaStories} name="TextArea" />
+
+# TextArea
+
+To use the TextArea import it like that:
+
+```tsx
+import { TextArea } from "@axa-fr/design-system-apollo-react";
+
+const MyComponent = () => (
+  <TextArea
+    id={inputId}
+    className={componentClassName}
+    ref={inputRef}
+    s
path: apps/apollo-stories/src/components/TextArea/TextArea.mdx
user: login: GuillaumeKESTEMAN
body: prop "s" oubliée
created_at: 2025-04-09T12:10:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,24 @@
+@use "TextAreaCommon";
+
+.af-form__input-textarea {
+  --input-text-area-border-radius: var(--radius-8);
+  --input-text-area-border-size: 1px;
+  --input-text-area-border-color: var(--axa-blue-53);
+
+  &--error {
+    --input-text-area-border-color: var(--axa-red-100);
+  }
+
+  &:disabled {
+    --input-text-area-border-color: var(--axa-gray-90);
+    --input-text-area-background: var(--axa-gray-96);
+  }
+
+  &:not(:disabled, &--error):focus {
+    --input-text-area-border-color: var(--axa-blue-100);
+  }
+
+  &:not(:disabled, &--error):hover {
+    --input-text-area-border-color: var(--axa-blue-100);
+  }
path: client/apollo/css/src/Form/TextArea/TextAreaApollo.scss
user: login: GuillaumeKESTEMAN
body: ```suggestion
  &:not(:disabled, &--error) {
    &:focus,
    &:hover {
      --input-text-area-border-color: var(--axa-blue-100);
    }
  }
```
created_at: 2025-04-09T12:14:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,50 @@
+@use "../../common/breakpoints" as breakpoints;
+@use "../../common/tokens";
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(148 / var(--font-size-base) * 1rem);
+  padding: 1rem 2.5rem 1rem 1rem;
+  border: 1px solid var(--input-text-area-border-color);
+  border-radius: var(--input-text-area-border-radius);
+  font: var(--font-family-base);
+  font-size: calc(16 / var(--font-size-base) * 1rem);
+  line-height: calc(20 / var(--font-size-base) * 1rem);
+  color: var(--axa-gray-36);
+  background-color: var(--white);
+  box-shadow: 0 0 0 1px var(--white);
+
+  @media (width > #{breakpoints.$breakpoint-md}) {
+    width: var(--size-384);
+    height: var(--size-148);
+    font-size: calc(18 / var(--font-size-base) * 1rem);
+    line-height: calc(24 / var(--font-size-base) * 1rem);
+  }
+
+  &--error {
+    border: 2px solid var(--input-text-area-border-color);
+    outline: none;
+  }
+
+  &:enabled,
+  &:focus,
+  &:active {
+    box-shadow: 0 0 0 1px var(--white);
+    outline: none;
+  }
+
+  &:disabled {
+    border: 1px solid var(--input-text-area-border-color);
+    background: var(--input-text-area-background);
+  }
+
+  &:not(:disabled, &--error):focus {
+    border: 2px solid var(--input-text-area-border-color);
+    box-shadow: 0 0 0 1px var(--input-text-area-border-color);
+  }
+
+  &:not(:disabled, &--error):hover {
+    border: 2px solid var(--input-text-area-border-color);
+    box-shadow: 0 0 0 1px var(--input-text-area-border-color);
+  }
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: GuillaumeKESTEMAN
body: ```suggestion
  &:not(:disabled, &--error) {
    &:focus,
    &:hover {
      border: 2px solid var(--input-text-area-border-color);
      box-shadow: 0 0 0 1px var(--input-text-area-border-color);
    }
  }
```
created_at: 2025-04-09T12:28:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+@use "TextAreaCommon";
+
+.af-form__input-textarea {
+  --input-text-area-border-radius: var(--radius-4);
+  --input-text-area-border-size: 1px;
+  --input-text-area-border-color: var(--color-gray-700);
+
+  &--error {
+    --input-text-area-border-color: var(--color-red-700);
+    --input-text-area-border-size: 2px;
+  }
+
+  &:disabled {
+    --input-text-area-border-color: var(--color-gray-400);
+    --input-text-area-background: var(--color-gray-200);
+  }
+
+  &:not(:disabled, &--error):focus {
+    --input-text-area-border-color: var(--color-axa);
+  }
+
+  &:not(:disabled, &--error):hover {
+    --input-text-area-border-color: var(--color-axa);
+  }
path: client/apollo/css/src/Form/TextArea/TextAreaLF.scss
user: login: GuillaumeKESTEMAN
body: ```suggestion
  &:not(:disabled, &--error) {
    &:focus,
    &:hover {
      --input-text-area-border-color: var(--color-axa);
    }
  }
```
created_at: 2025-04-09T12:29:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,50 @@
+@use "../../common/breakpoints" as breakpoints;
+@use "../../common/tokens";
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(148 / var(--font-size-base) * 1rem);
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: GuillaumeKESTEMAN
body: 148 côté apollo mais ça passe à 142 côté look&feel
created_at: 2025-04-09T12:45:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,50 @@
+@use "../../common/breakpoints" as breakpoints;
+@use "../../common/tokens";
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(148 / var(--font-size-base) * 1rem);
+  padding: 1rem 2.5rem 1rem 1rem;
+  border: 1px solid var(--input-text-area-border-color);
+  border-radius: var(--input-text-area-border-radius);
+  font: var(--font-family-base);
+  font-size: calc(16 / var(--font-size-base) * 1rem);
+  line-height: calc(20 / var(--font-size-base) * 1rem);
+  color: var(--axa-gray-36);
+  background-color: var(--white);
+  box-shadow: 0 0 0 1px var(--white);
+
+  @media (width > #{breakpoints.$breakpoint-md}) {
+    width: var(--size-384);
+    height: var(--size-148);
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: GuillaumeKESTEMAN
body: la width doit rester à 100% pour prendre la largeur du container et la height n'a pas besoin d'être redéfinie vu qu'elle ne bouge pas
created_at: 2025-04-09T12:45:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,6 +1,8 @@
 @use "TextAreaCommon";
 
 .af-form__input-textarea {
+  height: calc(142 / var(--font-size-base) * 1rem);
path: client/apollo/css/src/Form/TextArea/TextAreaLF.scss
user: login: GuillaumeKESTEMAN
body: ce serait mieux avec un token depuis le common, comme ça sur apollo on met le token de la height à 148 et côté lf à 142
created_at: 2025-04-09T13:40:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+import {
+  ComponentPropsWithRef,
+  forwardRef,
+  MouseEventHandler,
+  useId,
+} from "react";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { Button } from "../../Button/ButtonCommon";
+import { ItemLabel } from "../ItemLabel/ItemLabelCommon";
+import { ItemMessage } from "../ItemMessage/ItemMessageCommon";
+
+type Props = ComponentPropsWithRef<"textarea"> & {
+  classModifier?: string;
+  sideButtonLabel: string;
+  onSideButtonClick?: MouseEventHandler<HTMLButtonElement>;
+  helper?: string;
+  error?: string;
+  description?: string;
+  label?: string;
+  buttonLabel?: string;
+  onButtonClick?: MouseEventHandler<HTMLButtonElement>;
+} & Partial<ComponentPropsWithRef<typeof ItemMessage>>;
+
+const TextArea = forwardRef<HTMLTextAreaElement, Props>(
+  (
+    {
+      className,
+      classModifier = "",
+      label,
+      description,
+      helper,
+      error,
+      buttonLabel,
+      onButtonClick,
+      required,
+      sideButtonLabel,
+      onSideButtonClick,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const componentClassName = getComponentClassName(
+      "af-form__input-textarea",
+      className,
+      classModifier,
+    );
+
+    let inputId = useId();
path: client/apollo/react/src/Form/TextArea/TextAreaCommon.tsx
user: login: samuel-gomez-axa
body: on ne peut pas conditionner les hooks sinon react va râler 
created_at: 2025-04-09T13:45:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,47 @@
+@use "../../common/breakpoints" as breakpoints;
+@use "../../common/tokens";
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(148 / var(--font-size-base) * 1rem);
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: samuel-gomez-axa
body: je ne forcerais pas la hauteur ou au moins j'en ferais un token qui puisse être surchargé
created_at: 2025-04-09T13:49:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,23 @@
+@use "TextAreaCommon";
+
+.af-form__input-textarea {
+  --input-text-area-border-radius: var(--radius-8);
+  --input-text-area-border-size: 1px;
path: client/apollo/css/src/Form/TextArea/TextAreaApollo.scss
user: login: samuel-gomez-axa
body: token non utilisé
created_at: 2025-04-09T13:49:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,26 @@
+@use "TextAreaCommon";
+
+.af-form__input-textarea {
+  height: calc(142 / var(--font-size-base) * 1rem);
+
+  --input-text-area-border-radius: var(--radius-4);
+  --input-text-area-border-size: 1px;
+  --input-text-area-border-color: var(--color-gray-700);
+
+  &--error {
+    --input-text-area-border-color: var(--color-red-700);
+    --input-text-area-border-size: 2px;
path: client/apollo/css/src/Form/TextArea/TextAreaLF.scss
user: login: samuel-gomez-axa
body: je pense que l'on ajoute plutot un box-shadow en plus ce qui évite d'avoir un saut visuel
created_at: 2025-04-09T13:50:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -36,6 +36,7 @@
   --axa-blue-8: hsl(240deg, 33%, 91%);
   --axa-blue-80: hsl(240deg, 53%, 42%);
   --axa-blue-120: hsl(240deg, 100%, 22%);
+  --axa-blue-53: hsl(240deg, 39%, 53%);
path: client/apollo/css/src/common/tokens.scss
user: login: samuel-gomez-axa
body: ce token n'existe pas sur Apollo, à supprimer
created_at: 2025-04-09T13:51:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,10 @@
   --neutral-25: hsl(from var(--black) h s 80%);
   --neutral-14: hsl(from var(--black) h s 90%);
   --neutral-5: hsl(from var(--black) h s 96%);
+  --axa-gray-36: hsl(0deg, 0%, 36%);
path: client/apollo/css/src/common/tokens.scss
user: login: samuel-gomez-axa
body: supprimer tous les tokens ajoutés dans ce fichier sauf éventuellement le radius
created_at: 2025-04-09T13:52:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+import {
+  ComponentPropsWithRef,
+  forwardRef,
+  MouseEventHandler,
+  useId,
+} from "react";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { Button } from "../../Button/ButtonCommon";
path: client/apollo/react/src/Form/TextArea/TextAreaCommon.tsx
user: login: samuel-gomez-axa
body: ces 3 composants doivent être injectés voir le composant TextInput
created_at: 2025-04-09T13:53:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+import {
+  ComponentPropsWithRef,
+  forwardRef,
+  MouseEventHandler,
+  useId,
+} from "react";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { Button } from "../../Button/ButtonCommon";
+import { ItemLabel } from "../ItemLabel/ItemLabelCommon";
+import { ItemMessage } from "../ItemMessage/ItemMessageCommon";
+
+type Props = ComponentPropsWithRef<"textarea"> & {
+  classModifier?: string;
+  sideButtonLabel: string;
+  onSideButtonClick?: MouseEventHandler<HTMLButtonElement>;
+  helper?: string;
+  error?: string;
+  description?: string;
+  label?: string;
+  buttonLabel?: string;
+  onButtonClick?: MouseEventHandler<HTMLButtonElement>;
+} & Partial<ComponentPropsWithRef<typeof ItemMessage>>;
+
+const TextArea = forwardRef<HTMLTextAreaElement, Props>(
+  (
+    {
+      className,
+      classModifier = "",
+      label,
+      description,
+      helper,
+      error,
+      buttonLabel,
+      onButtonClick,
+      required,
+      sideButtonLabel,
+      onSideButtonClick,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const componentClassName = getComponentClassName(
+      "af-form__input-textarea",
+      className,
+      classModifier,
+    );
+
+    let inputId = useId();
+    inputId = otherProps.id || inputId;
+    const idError = useId();
+    const idLabel = useId();
+
+    return (
+      <div className="af-form__input-container">
+        {label && (
path: client/apollo/react/src/Form/TextArea/TextAreaCommon.tsx
user: login: samuel-gomez-axa
body: pas besoin de condition
created_at: 2025-04-09T13:53:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,87 @@
+import {
+  ComponentPropsWithRef,
+  forwardRef,
+  MouseEventHandler,
+  useId,
+} from "react";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { Button } from "../../Button/ButtonCommon";
+import { ItemLabel } from "../ItemLabel/ItemLabelCommon";
+import { ItemMessage } from "../ItemMessage/ItemMessageCommon";
+
+type Props = ComponentPropsWithRef<"textarea"> & {
+  classModifier?: string;
+  sideButtonLabel: string;
+  onSideButtonClick?: MouseEventHandler<HTMLButtonElement>;
+  helper?: string;
+  error?: string;
+  description?: string;
+  label?: string;
+  buttonLabel?: string;
+  onButtonClick?: MouseEventHandler<HTMLButtonElement>;
+} & Partial<ComponentPropsWithRef<typeof ItemMessage>>;
+
+const TextArea = forwardRef<HTMLTextAreaElement, Props>(
+  (
+    {
+      className,
+      classModifier = "",
+      label,
+      description,
+      helper,
+      error,
+      buttonLabel,
+      onButtonClick,
+      required,
+      sideButtonLabel,
+      onSideButtonClick,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const componentClassName = getComponentClassName(
+      "af-form__input-textarea",
+      className,
+      classModifier,
+    );
+
+    let inputId = useId();
+    inputId = otherProps.id || inputId;
+    const idError = useId();
+    const idLabel = useId();
+
+    return (
+      <div className="af-form__input-container">
+        {label && (
+          <div className="af-form__label-container">
path: client/apollo/react/src/Form/TextArea/TextAreaCommon.tsx
user: login: samuel-gomez-axa
body: cette div est déjà dans le composant ItemLabel
created_at: 2025-04-09T13:54:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,48 @@
+@use "../../common/breakpoints" as breakpoints;
+@use "../../common/tokens";
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: samuel-gomez-axa
body: il faut supprimer cet import

created_at: 2025-04-10T13:31:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,48 @@
+@use "../../common/breakpoints" as breakpoints;
+@use "../../common/tokens";
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(--input-text-area-height / var(--font-size-base) * 1rem);
+  padding: 1rem 2.5rem 1rem 1rem;
+  border: 1px solid var(--input-text-area-border-color);
+  border-radius: var(--input-text-area-border-radius);
+  font: var(--font-family-base);
+  font-size: calc(16 / var(--font-size-base) * 1rem);
+  line-height: calc(20 / var(--font-size-base) * 1rem);
+  color: var(--axa-gray-36);
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: samuel-gomez-axa
body: on ne devrait pas avoir de tokens de thème dans le common
created_at: 2025-04-10T13:31:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,48 @@
+@use "../../common/breakpoints" as breakpoints;
+@use "../../common/tokens";
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(--input-text-area-height / var(--font-size-base) * 1rem);
+  padding: 1rem 2.5rem 1rem 1rem;
+  border: 1px solid var(--input-text-area-border-color);
+  border-radius: var(--input-text-area-border-radius);
+  font: var(--font-family-base);
+  font-size: calc(16 / var(--font-size-base) * 1rem);
+  line-height: calc(20 / var(--font-size-base) * 1rem);
+  color: var(--axa-gray-36);
+  background-color: var(--white);
+  box-shadow: 0 0 0 1px var(--white);
+
+  @media (width > #{breakpoints.$breakpoint-md}) {
+    width: 100%;
+    font-size: calc(18 / var(--font-size-base) * 1rem);
+    line-height: calc(24 / var(--font-size-base) * 1rem);
+  }
+
+  &--error {
+    border: 2px solid var(--input-text-area-border-color);
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: samuel-gomez-axa
body: on devrait avoir 1px pour la bordure et 1px pour le box shadow

created_at: 2025-04-10T13:32:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,48 @@
+@use "../../common/breakpoints" as breakpoints;
+@use "../../common/tokens";
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(--input-text-area-height / var(--font-size-base) * 1rem);
+  padding: 1rem 2.5rem 1rem 1rem;
+  border: 1px solid var(--input-text-area-border-color);
+  border-radius: var(--input-text-area-border-radius);
+  font: var(--font-family-base);
+  font-size: calc(16 / var(--font-size-base) * 1rem);
+  line-height: calc(20 / var(--font-size-base) * 1rem);
+  color: var(--axa-gray-36);
+  background-color: var(--white);
+  box-shadow: 0 0 0 1px var(--white);
+
+  @media (width > #{breakpoints.$breakpoint-md}) {
+    width: 100%;
+    font-size: calc(18 / var(--font-size-base) * 1rem);
+    line-height: calc(24 / var(--font-size-base) * 1rem);
+  }
+
+  &--error {
+    border: 2px solid var(--input-text-area-border-color);
+    box-shadow: 1px solid var(--input-text-area-border-color);
+    outline: none;
+  }
+
+  &:enabled,
+  &:focus,
+  &:active {
+    box-shadow: 0 0 0 1px var(--white);
+    outline: none;
+  }
+
+  &:disabled {
+    border: 1px solid var(--input-text-area-border-color);
+    background: var(--input-text-area-background);
+  }
+
+  &:not(:disabled, &--error) {
+    &:focus,
+    &:hover {
+      border: 2px solid var(--input-text-area-border-color);
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: samuel-gomez-axa
body: on devrait avoir 1px pour la bordure et 1px pour le box shadow
created_at: 2025-04-10T13:32:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,33 @@
+import { render, screen } from "@testing-library/react";
+import { axe } from "jest-axe";
+import { TextArea } from "../TextAreaLF";
+
+describe("<TextArea />", () => {
+  test("should render component with default props", () => {
path: client/apollo/react/src/Form/TextArea/__tests__/TextArea.test.tsx
user: login: GuillaumeKESTEMAN
body: peut-être rajouter dans ton test un getByRole textbox pour vérifier que ton input est présent
created_at: 2025-04-14T08:07:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,48 @@
+@use "../../common/breakpoints" as breakpoints;
+
+.af-form__input-textarea {
+  width: 100%;
+  height: calc(--input-text-area-height / var(--font-size-base) * 1rem);
+  padding: 1rem 2.5rem 1rem 1rem;
path: client/apollo/css/src/Form/TextArea/TextAreaCommon.scss
user: login: pjbeaugendre
body: En regardant les maquettes il me semble que le padding est à 16px pour chaque côté
created_at: 2025-04-14T12:30:57Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-04-14T12:57:33Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=AxaFrance_design-system&pullRequest=1105) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1 New issue](https://sonarcloud.io/project/issues?id=AxaFrance_design-system&pullRequest=1105&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=AxaFrance_design-system&pullRequest=1105&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=AxaFrance_design-system&pullRequest=1105&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [86.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=AxaFrance_design-system&pullRequest=1105&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [1.2% Duplication on New Code](https://sonarcloud.io/component_measures?id=AxaFrance_design-system&pullRequest=1105&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=AxaFrance_design-system&pullRequest=1105)


author_association: NONE