Repository: AxaFrance/design-system
Pull request #1124: Création du composant DateInput
Author: login: maha-rkhissi
Labels: name: theme-client
description: Changes relatives to the client theme
name: theme-rospect
description: Changes relatives to the Propect theme
name: molecule
name: Création
Created: 2025-04-15T13:51:35Z | Merged: 2025-04-18T12:45:48Z

Added the DateInput Component

closes #814 

Linked issue #814: [AXA.fr] [Espace Client] [Molecule] Création du composant Input Date
Type : Molecule

Nom : Input Date

Objectif :
- Créer le composant "Input Date" en atomique pour la partie AXA.fr (Apollo) et Espace Client (Look & Feel)

---

Structure :

⚠️Utilisez toujours des éléments natifs (Ex : Date picker)
ℹ️ Utilisation de l'atome "item_label"
ℹ️ Utilisation de l'atome "item_message" (State : Error)

Device : --mob / --desk
Styles : --with_date_picker / -- whithout_date_picker
States : --default / --hover / --filled / --error / --disabled

![Image](https://github.com/user-attachments/assets/613d3819-4207-4f23-8a34-3fae57f60db3)

![Image](https://github.com/user-attachments/assets/32012fcb-790a-4449-b3f7-62f1405b3a4f)

----

Lien figma du composant : https://www.figma.com/design/vwprvN2ELfI50pjU6MK1Ea/Design-System-B2C?node-id=142-15169&t=5FclocJfHSKPkqD3-11


Diff:
diff --git a/apps/apollo-stories/src/components/Date/Date.stories.tsx b/apps/apollo-stories/src/components/Date/Date.stories.tsx
new file mode 100644
index 0000000000..14cb17926b
--- /dev/null
+++ b/apps/apollo-stories/src/components/Date/Date.stories.tsx
@@ -0,0 +1,104 @@
+import { DateInput } from "@axa-fr/design-system-apollo-react";
+import type { Meta, StoryObj } from "@storybook/react";
+
+const meta: Meta<typeof DateInput> = {
+  component: DateInput,
+  title: "Components/Form/Input/DateInput",
+  argTypes: { onChange: { action: "onChange" } },
+  args: {
+    name: "brithDate",
+    id: "uniqueId",
+    label: "Date de naissance",
+    required: true,
+    description: "Decription",
+    buttonLabel: "En savoir plus",
+    helper: "Informations complémentaires",
+  },
+};
+
+export default meta;
+
+type Story = StoryObj<typeof DateInput>;
+
+const render = ({
+  onChange,
+  ...args
+}: React.ComponentProps<typeof DateInput>) => (
+  <DateInput onChange={onChange} {...args} />
+);
+
+export const DateInputDefaultStory: Story = {
+  name: "Date",
+  render,
+  args: {
+    value: undefined,
+  },
+};
+
+export const DateInputDefaultWithDatePickerStory: Story = {
+  name: "Date with date picker",
+  render,
+  args: {
+    type: "date",
+    value: undefined,
+  },
+};
+
+export const DateInputFilledStory: Story = {
+  name: "Date filled",
+  render,
+  args: {
+    value: new Date("2000-09-12"),
+  },
+};
+
+export const DateInputFilledWithDatePickerStory: Story = {
+  name: "Date filled with date picker",
+  render,
+  args: {
+    value: new Date("2000-09-12"),
+    type: "date",
+  },
+};
+
+export const DateInputErrorStory: Story = {
+  name: "Date on error",
+  render,
+  args: {
+    classModifier: "error",
+    error: "Titre du message",
+    "aria-errormessage": undefined,
+    value: new Date("2067-09-12"),
+  },
+  argTypes: {
+    "aria-errormessage": {
+      control: { type: "date" },
+    },
+  },
+};
+
+export const DateInputErrorWithDatePickerStory: Story = {
+  name: "Date on error with date picker",
+  render,
+  args: {
+    classModifier: "error",
+    error: "Titre du message",
+    "aria-errormessage": undefined,
+    value: new Date("2067-09-12"),
+    type: "date",
+  },
+  argTypes: {
+    "aria-errormessage": {
+      control: { type: "date" },
+    },
+  },
+};
+
+export const DateInputDisabledStory: Story = {
+  name: "Date disabled",
+  render,
+  args: {
+    disabled: true,
+    value: new Date("2000-09-12"),
+  },
+};
diff --git a/apps/look-and-feel-stories/src/Date/Date.stories.tsx b/apps/look-and-feel-stories/src/Date/Date.stories.tsx
new file mode 100644
index 0000000000..097eaf3f56
--- /dev/null
+++ b/apps/look-and-feel-stories/src/Date/Date.stories.tsx
@@ -0,0 +1,99 @@
+import { DateInput } from "@axa-fr/design-system-look-and-feel-react";
+import { Meta, StoryObj } from "@storybook/react";
+
+const meta: Meta<typeof DateInput> = {
+  component: DateInput,
+  title: "Components/Form/Input/DateInput",
+  argTypes: { onChange: { action: "onChange" } },
+  args: {
+    name: "brithDate",
+    id: "uniqueId",
+    label: "Date de naissance",
+    required: true,
+    description: "Decription",
+    buttonLabel: "En savoir plus",
+    helper: "Informations complémentaires",
+  },
+};
+
+export default meta;
+
+type Story = StoryObj<typeof DateInput>;
+
+const render = ({
+  onChange,
+  ...args
+}: React.ComponentProps<typeof DateInput>) => (
+  <DateInput onChange={onChange} {...args} />
+);
+
+export const DateInputDefaultStory: Story = {
+  name: "Date",
+  render,
+};
+
+export const DateInputDefaultWithDatePickerStory: Story = {
+  name: "Date with date picker",
+  render,
+  args: {
+    type: "date",
+  },
+};
+
+export const DateInputFilledStory: Story = {
+  name: "Date filled",
+  render,
+  args: {
+    value: new Date("2025-01-01"),
+  },
+};
+
+export const DateInputFilledWithDatePickerStory: Story = {
+  name: "Date filled with date picker",
+  render,
+  args: {
+    value: new Date("2025-01-01"),
+    type: "date",
+  },
+};
+
+export const DateInputDisabledStory: Story = {
+  name: "Date disabled",
+  render,
+  args: {
+    disabled: true,
+  },
+};
+
+export const DateInputErrorStory: Story = {
+  name: "Date on error",
+  render,
+  args: {
+    classModifier: "error",
+    error: "Titre du message",
+    "aria-errormessage": undefined,
+    value: new Date("2080-01-01"),
+  },
+  argTypes: {
+    "aria-errormessage": {
+      control: { type: "date" },
+    },
+  },
+};
+
+export const DateInputErrorWithDatePickerStory: Story = {
+  name: "Date on error with date picker",
+  render,
+  args: {
+    classModifier: "error",
+    error: "Titre du message",
+    "aria-errormessage": undefined,
+    value: new Date("2080-01-01"),
+    type: "date",
+  },
+  argTypes: {
+    "aria-errormessage": {
+      control: { type: "date" },
+    },
+  },
+};
diff --git a/client/apollo/css/src/Form/DateInput/DateInputApollo.scss b/client/apollo/css/src/Form/DateInput/DateInputApollo.scss
new file mode 100644
index 0000000000..ade9a42e04
--- /dev/null
+++ b/client/apollo/css/src/Form/DateInput/DateInputApollo.scss
@@ -0,0 +1,36 @@
+@use "../../common/breakpoints" as breakpoints;
+
+@use "./DateInputCommon";
+
+.af-form {
+  &__input-helper {
+    --input-helper-color: var(--neutral-80);
+  }
+
+  &__input-date {
+    --input-border-color: var(--axa-blue-65);
+    --input-border-radius: var(--radius-8);
+    --input-bg-color: var(--white);
+    --input-date-color: var(--neutral-80);
+    --input-date-placeholder-color-filled: var(--axa-blue-100);
+
+    &:is(:hover, :focus, :active) {
+      --input-border-color: var(--axa-blue-100);
+    }
+
+    &[class*="--error"] {
+      --input-border-color: var(--red-alert-100);
+    }
+
+    &:disabled,
+    &:disabled:is(:hover, :focus, :active) {
+      --input-border-color: var(--neutral-50);
+      --input-date-color: var(--neutral-50);
+      --input-bg-color: var(--neutral-5);
+
+      + .af-form__input-helper {
+        --input-helper-color: var(--neutral-50);
+      }
+    }
+  }
+}
diff --git a/client/apollo/css/src/Form/DateInput/DateInputCommon.scss b/client/apollo/css/src/Form/DateInput/DateInputCommon.scss
new file mode 100644
index 0000000000..0b0924bf4f
--- /dev/null
+++ b/client/apollo/css/src/Form/DateInput/DateInputCommon.scss
@@ -0,0 +1,60 @@
+@use "../../common/breakpoints" as breakpoints;
+
+.af-form {
+  &__input-container {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    row-gap: calc(8 / var(--font-size-base) * 1rem);
+  }
+
+  &__input-date {
+    all: unset;
+    box-sizing: border-box;
+    width: 100%;
+    padding: calc(16 / var(--font-size-base) * 1rem);
+    border: 1px solid var(--input-border-color);
+    border-radius: var(--input-border-radius);
+    font: var(--font-family-base);
+    font-size: calc(16 / var(--font-size-base) * 1rem);
+    font-weight: 600;
+    line-height: 1.25em;
+    text-transform: uppercase;
+    color: var(--input-date-color);
+    background-color: var(--input-bg-color);
+
+    &::placeholder {
+      font-weight: 400;
+      color: var(--input-date-placeholder-color);
+    }
+
+    @media (width > #{breakpoints.$breakpoint-md}) {
+      font-size: calc(18 / var(--font-size-base) * 1rem);
+    }
+
+    &:is(:hover, :focus, :active) {
+      box-shadow: 0 0 0 1px var(--input-border-color) inset;
+    }
+
+    &:disabled,
+    &:disabled:is(:hover, :focus, :active) {
+      box-shadow: unset;
+      cursor: not-allowed;
+    }
+
+    &:valid:not([class*="--error"]) {
+      color: var(--input-date-placeholder-color-filled);
+    }
+  }
+
+  &__input-helper {
+    font-size: calc(14 / var(--font-size-base) * 1rem);
+    font-weight: 400;
+    line-height: 1.25em;
+    color: var(--input-helper-color);
+
+    @media (width > #{breakpoints.$breakpoint-md}) {
+      font-size: calc(16 / var(--font-size-base) * 1rem);
+    }
+  }
+}
diff --git a/client/apollo/css/src/Form/DateInput/DateInputLF.scss b/client/apollo/css/src/Form/DateInput/DateInputLF.scss
new file mode 100644
index 0000000000..037b626cc3
--- /dev/null
+++ b/client/apollo/css/src/Form/DateInput/DateInputLF.scss
@@ -0,0 +1,38 @@
+@use "../../common/breakpoints" as breakpoints;
+
+@use "./DateInputCommon";
+
+.af-form {
+  &__input-helper {
+    --input-helper-color: var(--color-gray-700);
+  }
+
+  &__input-date {
+    --input-border-color: var(--color-gray-700);
+    --input-border-radius: var(--default-border-radius);
+    --input-bg-color: var(--color-white);
+    --input-date-color: var(--color-gray-900);
+    --input-date-placeholder-color: var(--color-gray-700);
+    --input-date-placeholder-color-filled: var(--color-axa);
+
+    &:is(:hover, :focus, :active) {
+      --input-border-color: var(--color-axa);
+      --input-date-placeholder-color: var(--color-gray-900);
+    }
+
+    &[class*="--error"] {
+      --input-border-color: var(--color-red-700);
+    }
+
+    &:disabled,
+    &:disabled:is(:hover, :focus, :active) {
+      --input-border-color: var(--color-gray-400);
+      --input-date-color: var(--color-gray-500);
+      --input-bg-color: var(--color-gray-200);
+
+      + .af-form__input-helper {
+        --input-helper-color: var(--color-gray-500);
+      }
+    }
+  }
+}
diff --git a/client/apollo/css/src/apollo.scss b/client/apollo/css/src/apollo.scss
index f3e211fa96..a09c279487 100644
--- a/client/apollo/css/src/apollo.scss
+++ b/client/apollo/css/src/apollo.scss
@@ -18,3 +18,4 @@
 @use "./ProgressBar/ProgressBarApollo";
 @use "./ProgressBarGroup/ProgressBarGroupApollo";
 @use "./Stepper/StepperApollo";
+@use "./Form/DateInput/DateInputApollo";
diff --git a/client/apollo/css/src/look-and-feel.scss b/client/apollo/css/src/look-and-feel.scss
index 374fd2d49b..2154aaafbf 100644
--- a/client/apollo/css/src/look-and-feel.scss
+++ b/client/apollo/css/src/look-and-feel.scss
@@ -18,3 +18,4 @@
 @use "./ProgressBar/ProgressBarLF";
 @use "./ProgressBarGroup/ProgressBarGroupLF";
 @use "./Stepper/StepperLF";
+@use "./Form/DateInput/DateInputLF";
diff --git a/client/apollo/react/src/Form/DateInput/DateInput.helper.ts b/client/apollo/react/src/Form/DateInput/DateInput.helper.ts
new file mode 100644
index 0000000000..10ea74703f
--- /dev/null
+++ b/client/apollo/react/src/Form/DateInput/DateInput.helper.ts
@@ -0,0 +1,25 @@
+const MAXIMUM_SIZE_DATE = 10;
+
+export const formatDateInputValue = (
+  type: "date" | "text",
+  value?: Date | string | undefined,
+): string | undefined => {
+  if (!value) return undefined;
+
+  if (value instanceof Date) {
+    if (type === "date") {
+      return value.toISOString().slice(0, MAXIMUM_SIZE_DATE);
+    }
+    if (type === "text") {
+      const day = String(value.getDate()).padStart(2, "0");
+      const month = String(value.getMonth() + 1).padStart(2, "0");
+      const year = String(value.getFullYear()).padStart(4, "0");
+      return `${day}/${month}/${year}`;
+    }
+  }
+  if (typeof value === "string") {
+    return value;
+  }
+
+  return undefined;
+};
diff --git a/client/apollo/react/src/Form/DateInput/DateInputApollo.tsx b/client/apollo/react/src/Form/DateInput/DateInputApollo.tsx
new file mode 100644
index 0000000000..fca4e83b0a
--- /dev/null
+++ b/client/apollo/react/src/Form/DateInput/DateInputApollo.tsx
@@ -0,0 +1,18 @@
+import "@axa-fr/design-system-apollo-css/dist/Form/DateInput/DateInputApollo.scss";
+import type { ComponentProps } from "react";
+import { ItemLabel } from "../ItemLabel/ItemLabelApollo";
+import { ItemMessage } from "../ItemMessage/ItemMessageApollo";
+import { DateInput as DateInputCommon } from "./DateInputCommon";
+
+export const DateInput = (
+  props: Omit<
+    ComponentProps<typeof DateInputCommon>,
+    "ItemLabelComponent" | "ItemMessageComponent"
+  >,
+) => (
+  <DateInputCommon
+    {...props}
+    ItemLabelComponent={ItemLabel}
+    ItemMessageComponent={ItemMessage}
+  />
+);
diff --git a/client/apollo/react/src/Form/DateInput/DateInputCommon.tsx b/client/apollo/react/src/Form/DateInput/DateInputCommon.tsx
new file mode 100644
index 0000000000..c518e9bd64
--- /dev/null
+++ b/client/apollo/react/src/Form/DateInput/DateInputCommon.tsx
@@ -0,0 +1,108 @@
+import {
+  ComponentProps,
+  ComponentPropsWithRef,
+  ComponentType,
+  forwardRef,
+  useId,
+} from "react";
+import { ItemLabel } from "../ItemLabel/ItemLabelCommon";
+import { ItemMessage } from "../ItemMessage/ItemMessageCommon";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { formatDateInputValue } from "./DateInput.helper";
+
+type DateInputProps = Omit<ComponentPropsWithRef<"input">, "value"> & {
+  classModifier?: string;
+  defaultValue?: Date | string;
+  value?: Date | string;
+  helper?: string;
+  error?: string;
+  success?: string;
+  label: ComponentProps<typeof ItemLabel>["label"];
+  type?: "text" | "date";
+  ItemLabelComponent: ComponentType<
+    Omit<ComponentProps<typeof ItemLabel>, "ButtonComponent">
+  >;
+  ItemMessageComponent: ComponentType<ComponentProps<typeof ItemMessage>>;
+} & Partial<ComponentPropsWithRef<typeof ItemLabel>>;
+
+const DateInput = forwardRef<HTMLInputElement, DateInputProps>(
+  (
+    {
+      className,
+      classModifier = "",
+      defaultValue,
+      value,
+      placeholder = "JJ/MM/AAAA",
+      helper,
+      error,
+      success,
+      label,
+      description,
+      buttonLabel,
+      onButtonClick,
+      ItemLabelComponent,
+      ItemMessageComponent,
+      required,
+      "aria-errormessage": ariaErrormessage,
+      type = "text",
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const componentClassName = getComponentClassName(
+      "af-form__input-date",
+      className ?? "",
+      classModifier + (error || ariaErrormessage ? " error" : ""),
+    );
+
+    let inputId = useId();
+    inputId = otherProps.id ?? inputId;
+    const idMessage = useId();
+    const idHelp = useId();
+    const idLabel = useId();
+
+    return (
+      <div className="af-form__input-container">
+        <ItemLabelComponent
+          label={label}
+          description={description}
+          buttonLabel={buttonLabel}
+          onButtonClick={onButtonClick}
+          required={required}
+          inputId={inputId}
+          idLabel={idLabel}
+        />
+        <input
+          {...otherProps}
+          id={inputId}
+          className={componentClassName}
+          type={type}
+          placeholder={placeholder || ""}
+          ref={inputRef}
+          defaultValue={formatDateInputValue(type, defaultValue)}
+          value={formatDateInputValue(type, value)}
+          aria-labelledby={idLabel}
+          aria-errormessage={ariaErrormessage ?? idMessage}
+          aria-invalid={Boolean(error ?? ariaErrormessage)}
+          aria-describedby={idHelp}
+          required={required}
+        />
+        {helper && (
+          <span id={idHelp} className="af-form__input-helper">
+            {helper}
+          </span>
+        )}
+
+        <ItemMessageComponent
+          id={idMessage}
+          message={error ?? success}
+          messageType={error ? "error" : "success"}
+        />
+      </div>
+    );
+  },
+);
+
+DateInput.displayName = "DateInput";
+
+export { DateInput };
diff --git a/client/apollo/react/src/Form/DateInput/DateInputLF.tsx b/client/apollo/react/src/Form/DateInput/DateInputLF.tsx
new file mode 100644
index 0000000000..b974b16b11
--- /dev/null
+++ b/client/apollo/react/src/Form/DateInput/DateInputLF.tsx
@@ -0,0 +1,18 @@
+import "@axa-fr/design-system-apollo-css/dist/Form/DateInput/DateInputLF.scss";
+import { ComponentProps } from "react";
+import { ItemLabel } from "../ItemLabel/ItemLabelLF";
+import { ItemMessage } from "../ItemMessage/ItemMessageLF";
+import { DateInput as DateInputCommon } from "./DateInputCommon";
+
+export const DateInput = (
+  props: Omit<
+    ComponentProps<typeof DateInputCommon>,
+    "ItemLabelComponent" | "ItemMessageComponent"
+  >,
+) => (
+  <DateInputCommon
+    {...props}
+    ItemLabelComponent={ItemLabel}
+    ItemMessageComponent={ItemMessage}
+  />
+);
diff --git a/client/apollo/react/src/Form/DateInput/__tests__/DateInput.helper.test.tsx b/client/apollo/react/src/Form/DateInput/__tests__/DateInput.helper.test.tsx
new file mode 100644
index 0000000000..37fa25cb38
--- /dev/null
+++ b/client/apollo/react/src/Form/DateInput/__tests__/DateInput.helper.test.tsx
@@ -0,0 +1,51 @@
+import { formatDateInputValue } from "../DateInput.helper";
+
+describe("formatDateInputValue", () => {
+  it("should return undefined if value is undefined", () => {
+    expect(formatDateInputValue("date", undefined)).toBeUndefined();
+    expect(formatDateInputValue("text", undefined)).toBeUndefined();
+  });
+
+  it.each([
+    ["2025-04-18T00:00:00Z", "2025-04-18"],
+    ["2025-04-18", "2025-04-18"],
+    ["0005-04-18", "0005-04-18"],
+  ])(
+    "should format a Date object to ISO date format when format is 'date'",
+    (date, expected) => {
+      expect(formatDateInputValue("date", new Date(date))).toBe(expected);
+    },
+  );
+
+  it.each([
+    ["2025-04-18T00:00:00Z", "18/04/2025"],
+    ["2025-04-18", "18/04/2025"],
+    ["0005-04-18", "18/04/0005"],
+  ])(
+    "should format a Date object object to string when format is 'text'",
+    (date, expected) => {
+      expect(formatDateInputValue("text", new Date(date))).toBe(expected);
+    },
+  );
+
+  it("should return the string value as is", () => {
+    const value = "2025-04-18";
+    expect(formatDateInputValue("date", value)).toStrictEqual(value);
+    expect(formatDateInputValue("text", value)).toStrictEqual(value);
+  });
+
+  it("should return undefined for invalid value types", () => {
+    expect(
+      formatDateInputValue("date", 123 as unknown as Date),
+    ).toBeUndefined();
+    expect(
+      formatDateInputValue("text", 123 as unknown as Date),
+    ).toBeUndefined();
+  });
+
+  it("should handle edge cases for Date objects", () => {
+    const date = new Date("0001-01-01");
+    expect(formatDateInputValue("date", date)).toBe("0001-01-01");
+    expect(formatDateInputValue("text", date)).toBe("01/01/0001");
+  });
+});
diff --git a/client/apollo/react/src/Form/DateInput/__tests__/DateInput.test.tsx b/client/apollo/react/src/Form/DateInput/__tests__/DateInput.test.tsx
new file mode 100644
index 0000000000..28d5ff8b57
--- /dev/null
+++ b/client/apollo/react/src/Form/DateInput/__tests__/DateInput.test.tsx
@@ -0,0 +1,63 @@
+import { render, screen } from "@testing-library/react";
+import { axe } from "jest-axe";
+import { DateInput } from "../DateInputApollo";
+
+describe("<DateInput />", () => {
+  it("renders the DateInput component with label only", () => {
+    render(<DateInput label="Test Label" />);
+    expect(screen.getByText("Test Label")).toBeInTheDocument();
+  });
+
+  it("renders fully", () => {
+    render(
+      <DateInput
+        id="id"
+        label="test"
+        name="name"
+        placeholder="placeholder"
+        error="error"
+        value="01/01/2025"
+        onChange={() => {}}
+        required
+        description="description"
+        buttonLabel="buttonLabel"
+        helper="helper"
+      />,
+    );
+
+    const dateInput = screen.getByLabelText(/test/);
+    expect(dateInput).toBeInTheDocument();
+    expect(dateInput).toHaveAccessibleDescription("helper");
+    expect(dateInput).toHaveProperty("placeholder", "placeholder");
+    expect(dateInput).toHaveAccessibleErrorMessage("error");
+    expect(dateInput).toHaveValue("01/01/2025");
+    expect(dateInput).toHaveClass("af-form__input-date");
+    expect(dateInput).toHaveAttribute("name", "name");
+    expect(dateInput).toHaveAttribute("type", "text");
+    expect(dateInput).toBeRequired();
+    expect(dateInput).toHaveAttribute("id", "id");
+  });
+
+  it("renders with a date picker and value is a Date object", () => {
+    render(
+      <DateInput label="test" type="date" value={new Date("2025-01-01")} />,
+    );
+    const dateInput = screen.getByLabelText(/test/);
+    expect(dateInput).toBeInTheDocument();
+    expect(dateInput).toHaveValue("2025-01-01");
+  });
+
+  it("renders without a date picker and value is a Date object", () => {
+    render(<DateInput label="test" value={new Date("2025-01-01")} />);
+    const dateInput = screen.getByLabelText(/test/);
+    expect(dateInput).toBeInTheDocument();
+    expect(dateInput).toHaveValue("01/01/2025");
+  });
+});
+
+describe("A11Y", () => {
+  it("shouldn't have an accessibility violation <DateInput />", async () => {
+    const { container } = render(<DateInput label="test" />);
+    expect(await axe(container)).toHaveNoViolations();
+  });
+});
diff --git a/client/apollo/react/src/index.ts b/client/apollo/react/src/index.ts
index 3a69838943..51540ceabe 100644
--- a/client/apollo/react/src/index.ts
+++ b/client/apollo/react/src/index.ts
@@ -33,7 +33,6 @@ export { Divider } from "./Divider/DividerApollo";
 export { ClickIcon } from "./ClickIcon/ClickIconApollo";
 export { Toggle } from "./Toggle/ToggleApollo";
 export { BasePicture } from "./BasePicture/BasePictureApollo";
-
 export {
   Message,
   messageVariants,
@@ -42,3 +41,4 @@ export {
 export { ProgressBar } from "./ProgressBar/ProgressBarApollo";
 export { ProgressBarGroup } from "./ProgressBarGroup/ProgressBarGroupApollo";
 export { Stepper } from "./Stepper/StepperApollo";
+export { DateInput } from "./Form/DateInput/DateInputApollo";
diff --git a/client/apollo/react/src/indexLF.ts b/client/apollo/react/src/indexLF.ts
index 3daa2ea86c..c77f0a9698 100644
--- a/client/apollo/react/src/indexLF.ts
+++ b/client/apollo/react/src/indexLF.ts
@@ -36,3 +36,4 @@ export {
 export { ProgressBar } from "./ProgressBar/ProgressBarLF";
 export { ProgressBarGroup } from "./ProgressBarGroup/ProgressBarGroupLF";
 export { Stepper } from "./Stepper/StepperLF";
+export { DateInput } from "./Form/DateInput/DateInputLF";
diff --git a/client/look-and-feel/react/src/Form/Date/Date.tsx b/client/look-and-feel/react/src/Form/Date/Date.tsx
new file mode 100644
index 0000000000..3173c316e3
--- /dev/null
+++ b/client/look-and-feel/react/src/Form/Date/Date.tsx
@@ -0,0 +1,2 @@
+/* eslint-disable import/no-extraneous-dependencies */
+export { DateInput } from "@axa-fr/design-system-apollo-react/lf";
diff --git a/client/look-and-feel/react/src/index.ts b/client/look-and-feel/react/src/index.ts
index 194b17c13c..f8a25dfbae 100644
--- a/client/look-and-feel/react/src/index.ts
+++ b/client/look-and-feel/react/src/index.ts
@@ -22,6 +22,7 @@ export { Radio, RadioSelect } from "./Form/Radio";
 export { Select } from "./Form/Select/Select";
 export { TextInput } from "./Form/Text/Text";
 export { TextArea } from "./Form/TextArea/TextArea";
+export { DateInput } from "./Form/Date/Date";
 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-16T09:38:41Z
user: login: pplancq
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T12:19:49Z
user: login: pplancq
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T12:21:07Z
user: login: maha-rkhissi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T14:59:38Z
user: login: maha-rkhissi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T15:03:14Z
user: login: maha-rkhissi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T15:07:44Z
user: login: pplancq
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T15:12:49Z
user: login: maha-rkhissi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T15:32:29Z
user: login: pjbeaugendre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T06:39:43Z
user: login: pjbeaugendre
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T06:56:07Z
user: login: maha-rkhissi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T22:10:14Z
user: login: maha-rkhissi
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T23:39:07Z
user: login: pplancq
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T09:57:18Z
user: login: baptistefroger
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T12:04:33Z
user: login: samuel-gomez-axa
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T12:41:43Z
user: login: pjbeaugendre
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T12:44:39Z

Review comments:
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: pjbeaugendre
body: Je n'ai jamais vu de fichier Atom.tsx dans le reste du projet. Est-ce que ça a été vu avec Sam ou quelqu'un d'autre ?
created_at: 2025-04-16T08:51:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,59 @@
+import { render, screen } from "@testing-library/react";
+import { DateInput } from "../DateInputApollo";
+
+describe("<DateInput />", () => {
+  it("renders the DateInput component with label only", () => {
+    render(<DateInput label="Test Label" />);
+    expect(screen.getByText("Test Label")).toBeInTheDocument();
+  });
+
+  it("renders fully", () => {
+    render(
+      <DateInput
+        id="id"
+        label="test"
+        name="name"
+        placeholder="placeholder"
+        error="error"
+        value="01/01/2025"
+        onChange={() => {}}
+        required
+        description="description"
+        buttonLabel="buttonLabel"
+        helper="helper"
+      />,
+    );
+
+    const dateInput = screen.getByLabelText(/test/);
+    expect(dateInput).toBeInTheDocument();
+    expect(dateInput).toHaveAccessibleDescription("helper");
+    expect(dateInput).toHaveProperty("placeholder", "placeholder");
+    expect(dateInput).toHaveAccessibleErrorMessage("error");
+    expect(dateInput).toHaveValue("01/01/2025");
+    expect(dateInput).toHaveClass("af-form__input-date");
+    expect(dateInput).toHaveAttribute("name", "name");
+    expect(dateInput).toHaveAttribute("type", "text");
+    expect(dateInput).toBeRequired();
+    expect(dateInput).toHaveAttribute("id", "id");
+  });
+
+  it("renders with a date picker and value is a Date object", () => {
+    render(
+      <DateInput
+        label="test"
+        hideDatePicker={false}
+        value={new Date("2025-01-01")}
+      />,
+    );
+    const dateInput = screen.getByLabelText(/test/);
+    expect(dateInput).toBeInTheDocument();
+    expect(dateInput).toHaveValue("2025-01-01");
+  });
+
+  it("renders without a date picker and value is a Date object", () => {
+    render(<DateInput label="test" value={new Date("2025-01-01")} />);
+    const dateInput = screen.getByLabelText(/test/);
+    expect(dateInput).toBeInTheDocument();
+    expect(dateInput).toHaveValue("01/01/2025");
+  });
+});
path: client/apollo/react/src/Form/DateInput/__tests__/DateInput.test.tsx
user: login: pjbeaugendre
body: Tu peux ajouter un test Axe pour l'accessibilité
Petit exemple ici si tu veux: https://github.com/AxaFrance/design-system/blob/main/client/apollo/react/src/Form/TextInput/__tests__/TextInputLF.test.tsx#L49-L55
created_at: 2025-04-16T09:04:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+@use "../../common/breakpoints" as breakpoints;
path: client/apollo/css/src/Form/DateInput/DateInputApollo.scss
user: login: pjbeaugendre
body: Lorsque l'input est fill et qu'on retire le focus, j'ai l'impression que la border n'est pas suffisamment épaisse
created_at: 2025-04-16T09:11:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,68 @@
+@use "../../common/breakpoints" as breakpoints;
path: client/apollo/css/src/Form/DateInput/DateInputCommon.scss
user: login: pjbeaugendre
body: Le hover ne se fait pas sur l'entièreté de la zone 
created_at: 2025-04-16T09:21:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+@use "../../common/breakpoints" as breakpoints;
path: client/apollo/css/src/Form/DateInput/DateInputApollo.scss
user: login: pjbeaugendre
body: Lorsque l'input est fill et correct, le texte doit être bleu
created_at: 2025-04-16T09:21:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: pjbeaugendre
body: J'ai l'impression que la date n'est pas auto formaté sur l'input date classique
created_at: 2025-04-16T09:24:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
+import { formatDateInputValue } from "../../utilities/helpers/date";
+
+type DateProps = Omit<ComponentPropsWithRef<"input">, "value"> & {
+  defaultValue?: Date | string;
+  value?: Date | string;
+  hideDatePicker?: boolean;
+  placeholder: string;
+};
+
+const DateAtom = forwardRef<HTMLInputElement, DateProps>(
+  (
+    {
+      className,
+      defaultValue,
+      value,
+      hideDatePicker,
+      placeholder,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const format = hideDatePicker ? "text" : "date";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: pjbeaugendre
body: Avec le datePicker, le format de date est anglais
![image](https://github.com/user-attachments/assets/286db370-3432-48e5-bf91-50623e9a4b67)

created_at: 2025-04-16T09:26:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,68 @@
+@use "../../common/breakpoints" as breakpoints;
+
+.af-form {
+  &__input-container {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    row-gap: calc(8 / var(--font-size-base) * 1rem);
+  }
+
+  &__input-variant {
+    display: grid;
+    width: 100%;
+    padding: calc(16 / var(--font-size-base) * 1rem);
+    border: 1px solid var(--input-border-color);
+    border-radius: var(--input-border-radius);
+    grid-template-columns: auto min-content;
+    align-items: center;
+    color: var(--input-text-color);
+    background-color: var(--input-bg-color);
+
+    &:has(> input ~ *) {
+      column-gap: calc(8 / var(--font-size-base) * 1rem);
+    }
+
+    > input {
+      all: unset;
+      font-size: calc(16 / var(--font-size-base) * 1rem);
+      font-weight: 600;
+      line-height: 1.25em;
path: client/apollo/css/src/Form/DateInput/DateInputCommon.scss
user: login: pjbeaugendre
body: Lorsqu'on n'a pas le datePicker, la height est un tout petit peu trop petite (54px au lieu de 56px)
created_at: 2025-04-16T09:31:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,25 @@
+const MAXIMUM_SIZE_DATE = 10;
+
+export const formatDateInputValue = (
+  format: "date" | "text",
+  value?: Date | string | undefined,
+): string | undefined => {
+  if (!value) return undefined;
+
+  if (value instanceof Date) {
+    if (format === "date") {
+      return value.toISOString().slice(0, MAXIMUM_SIZE_DATE);
+    }
+    if (format === "text") {
+      const day = String(value.getDate()).padStart(2, "0");
+      const month = String(value.getMonth() + 1).padStart(2, "0");
+      const year = value.getFullYear();
path: client/apollo/react/src/utilities/helpers/date.ts
user: login: pplancq
body: Attention le `getFullYear()` ne retourne pas l'année sur 4 chiffres systématiquement ce qui nous a posé des problème coté slash. Pour plus d'info base toi sur la PR #820 pour changer cela.
Il faudrait ajouter un `.padStart(4 "0");`
created_at: 2025-04-16T12:10:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+import {
+  ComponentProps,
+  ComponentPropsWithRef,
+  ComponentType,
+  forwardRef,
+  useId,
+} from "react";
+import { ItemLabel } from "../ItemLabel/ItemLabelCommon";
+import { ItemMessage } from "../ItemMessage/ItemMessageCommon";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { DateAtom } from "./DateAtom";
+
+type DateInputProps = Omit<ComponentPropsWithRef<"input">, "value"> & {
+  classModifier?: string;
+  defaultValue?: Date | string;
+  value?: Date | string;
+  helper?: string;
+  error?: string;
+  success?: string;
+  label: ComponentProps<typeof ItemLabel>["label"];
+  hideDatePicker?: boolean;
+  ItemLabelComponent: ComponentType<
+    Omit<ComponentProps<typeof ItemLabel>, "ButtonComponent">
+  >;
+  ItemMessageComponent: ComponentType<ComponentProps<typeof ItemMessage>>;
+} & Partial<ComponentPropsWithRef<typeof ItemLabel>>;
+
+const DateInput = forwardRef<HTMLInputElement, DateInputProps>(
+  (
+    {
+      className,
+      classModifier = "",
path: client/apollo/react/src/Form/DateInput/DateInputCommon.tsx
user: login: pplancq
body: Coté Apollo on n'utilise pas de `classModifier` pour les composants on préfère l'utilisation de props plus précise comme variant, size, etc...
created_at: 2025-04-16T12:17:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: pplancq
body: Je suis d'accord `DateAtom` c'est pas très parlant comme namming, par contre au vue du composant et ce sont utilisation je dirais plus `DateBase` ou `DateCore`.
created_at: 2025-04-16T12:21:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
+import { formatDateInputValue } from "../../utilities/helpers/date";
+
+type DateProps = Omit<ComponentPropsWithRef<"input">, "value"> & {
+  defaultValue?: Date | string;
+  value?: Date | string;
+  hideDatePicker?: boolean;
+  placeholder: string;
+};
+
+const DateAtom = forwardRef<HTMLInputElement, DateProps>(
+  (
+    {
+      className,
+      defaultValue,
+      value,
+      hideDatePicker,
+      placeholder,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const format = hideDatePicker ? "text" : "date";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: maha-rkhissi
body: @pjbeaugendre c'est le comportement natif de `<input type="date" />`, qui se base sur les paramètres _locale_ du navigateur pour déterminer le format de la date affiché. J'ai utilisé l'input date natif parce que c'est explicitement demandé dans l'issue. Cette demande fait que je n'ai pas pu agir sur plusieurs autres éléments tels que l'icône, le CSS du date picker et le placeholder. J'en discuterai plus en détail avec Samuel. 
created_at: 2025-04-16T14:59:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: maha-rkhissi
body: @pjbeaugendre normalement c'est géré dans [date.ts](https://github.com/AxaFrance/design-system/pull/1124/files/13ba58349b8acd7ad9283b7cd93dc423a14cd8c6#diff-08a4d8a3f42b907a8f6c6038affb8369ab60920c4bb606260714c2b9a2176838) ? Tu peux me donner plus de détails pls?
created_at: 2025-04-16T15:03:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
+import { formatDateInputValue } from "../../utilities/helpers/date";
+
+type DateProps = Omit<ComponentPropsWithRef<"input">, "value"> & {
+  defaultValue?: Date | string;
+  value?: Date | string;
+  hideDatePicker?: boolean;
+  placeholder: string;
+};
+
+const DateAtom = forwardRef<HTMLInputElement, DateProps>(
+  (
+    {
+      className,
+      defaultValue,
+      value,
+      hideDatePicker,
+      placeholder,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const format = hideDatePicker ? "text" : "date";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: maha-rkhissi
body: @pjbeaugendre ex de ce que ça donnerai avec un browser fr 
![image](https://github.com/user-attachments/assets/f1eb3a5a-c0b3-4a5e-9244-2048a728f073)

created_at: 2025-04-16T15:07:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
+import { formatDateInputValue } from "../../utilities/helpers/date";
+
+type DateProps = Omit<ComponentPropsWithRef<"input">, "value"> & {
+  defaultValue?: Date | string;
+  value?: Date | string;
+  hideDatePicker?: boolean;
+  placeholder: string;
+};
+
+const DateAtom = forwardRef<HTMLInputElement, DateProps>(
+  (
+    {
+      className,
+      defaultValue,
+      value,
+      hideDatePicker,
+      placeholder,
+      ...otherProps
+    },
+    inputRef,
+  ) => {
+    const format = hideDatePicker ? "text" : "date";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: pplancq
body: Il me semble que pour le moment il est impossible de personnalisé le date picker,le placeholder et l'icone de l'input date natif. 
Mais pour moi cela ne pose pas de problème car l'input natif est accessible nativement.
Et vue qu'aujourd'hui on peut enfin styliser un select natif (chromium uniquement) je me dit un jour l'input date le sera aussi.
created_at: 2025-04-16T15:12:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: maha-rkhissi
body: renommé [DateBase.tsx](https://github.com/AxaFrance/design-system/pull/1124/files#diff-b46bff53d81f9b634dbd3bd7bc7f2b881363afa687e44b592f854d5099266869)
created_at: 2025-04-16T15:32:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: pjbeaugendre
body: Je pense que c'est au niveau du composant. Lorsque je le teste, l'input rentré n'est pas formaté ce qui donne le résultat suivant

![image](https://github.com/user-attachments/assets/45c9b9b6-ff98-483c-ad9a-93290f34f82c)

created_at: 2025-04-17T06:39:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: pjbeaugendre
body: Je peux rentrer des caractères n'étant pas des chiffres
created_at: 2025-04-17T06:56:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,40 @@
+import { ComponentPropsWithRef, forwardRef } from "react";
path: client/apollo/react/src/Form/DateInput/DateAtom.tsx
user: login: maha-rkhissi
body: les composants du DS sont stateless
created_at: 2025-04-17T22:10:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,108 @@
+import {
+  ComponentProps,
+  ComponentPropsWithRef,
+  ComponentType,
+  forwardRef,
+  useId,
+} from "react";
+import { ItemLabel } from "../ItemLabel/ItemLabelCommon";
+import { ItemMessage } from "../ItemMessage/ItemMessageCommon";
+import { getComponentClassName } from "../../utilities/getComponentClassName";
+import { DateAtom } from "./DateAtom";
+
+type DateInputProps = Omit<ComponentPropsWithRef<"input">, "value"> & {
+  classModifier?: string;
+  defaultValue?: Date | string;
+  value?: Date | string;
+  helper?: string;
+  error?: string;
+  success?: string;
+  label: ComponentProps<typeof ItemLabel>["label"];
+  hideDatePicker?: boolean;
+  ItemLabelComponent: ComponentType<
+    Omit<ComponentProps<typeof ItemLabel>, "ButtonComponent">
+  >;
+  ItemMessageComponent: ComponentType<ComponentProps<typeof ItemMessage>>;
+} & Partial<ComponentPropsWithRef<typeof ItemLabel>>;
+
+const DateInput = forwardRef<HTMLInputElement, DateInputProps>(
+  (
+    {
+      className,
+      classModifier = "",
path: client/apollo/react/src/Form/DateInput/DateInputCommon.tsx
user: login: maha-rkhissi
body: vu avec Samuel, on se focus dans un premier temps sur la migration et on refait une pass après pour enlever les classmodifier
created_at: 2025-04-17T23:39:07Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-04-18T08:36:26Z
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=1124) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [2 New issues](https://sonarcloud.io/project/issues?id=AxaFrance_design-system&pullRequest=1124&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=1124&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=1124&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [95.1% Coverage on New Code](https://sonarcloud.io/component_measures?id=AxaFrance_design-system&pullRequest=1124&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=AxaFrance_design-system&pullRequest=1124&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=AxaFrance_design-system&pullRequest=1124)


author_association: NONE