diff --git a/packages/codemod/transformations/core/v2-to-v3/__tests__/text-field-component-migration.test.ts b/packages/codemod/transformations/core/v2-to-v3/__tests__/text-field-component-migration.test.ts
new file mode 100644
index 0000000000..9f7c098c4b
--- /dev/null
+++ b/packages/codemod/transformations/core/v2-to-v3/__tests__/text-field-component-migration.test.ts
@@ -0,0 +1,319 @@
+import transform from "../text-field-component-migration";
+import { defineInlineTest } from "jscodeshift/src/testUtils";
+
+function prependImport(source: string): string {
+ return `
+ import { TextField } from "monday-ui-react-core";
+ ${source}
+ `;
+}
+
+describe("TextField component migration", () => {
+ describe("dataTestId to data-testId", () => {
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should update 'dataTestId' to 'data-testid'"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(`
`),
+ prependImport(`
`),
+ "should update 'dataTestId' to 'data-testid' in a nested structure"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should update 'dataTestId' to 'data-testid' while maintaining other props"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(
+ `
+ <>
+
+
+ >`
+ ),
+ prependImport(`
+ <>
+
+
+ >`),
+ "should handle multiple instances of TextField each with 'dataTestId'"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should not change when when both 'dataTestId' and 'data-testid' props exist with different literal values"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should remove 'dataTestId' when both 'dataTestId' and 'data-testid' props exist and have same values"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should not change when when both 'dataTestId' and 'data-testid' props exist and have different complex values"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should remove 'dataTestId' when when both 'dataTestId' and 'data-testid' props exist with same literal values while one is inside an expression"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ ``,
+ ``,
+ "should not change when no import even if 'dataTestId' prop exists"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should not affect other components with 'dataTestId'"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ `
+ import { TextField } from "other-library";
+
+ `,
+ `
+ import { TextField } from "other-library";
+
+ `,
+ "should not change when 'TextField' is not imported from vibe"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ `
+ import { OtherComponent as TextField } from "other-library";
+
+ `,
+ `
+ import { OtherComponent as TextField } from "other-library";
+
+ `,
+ "should not change when 'TextField' is an alias for another component that is not from vibe"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ `
+ import { OtherComponent as TextField } from "monday-ui-react-core";
+
+ `,
+ `
+ import { OtherComponent as TextField } from "monday-ui-react-core";
+
+ `,
+ "should not change when 'TextField' is an alias for another component from vibe"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ `
+ import { TextField as VibeComponent } from "monday-ui-react-core";
+
+ `,
+ `
+ import { TextField as VibeComponent } from "monday-ui-react-core";
+
+ `,
+ "should change when 'TextField' is imported with alias from vibe"
+ );
+ });
+
+ describe('remove "withReadOnlyStyle" prop', () => {
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should remove 'withReadOnlyStyle' prop"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should remove 'withReadOnlyStyle' prop if given with a value"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(
+ `
+ <>
+
+
+ >`
+ ),
+ prependImport(`
+ <>
+
+
+ >`),
+ "should handle multiple instances of TextField each with 'withReadOnlyStyle'"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ ``,
+ ``,
+ "should not change when no import even if 'withReadOnlyStyle' prop exists"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should not affect other components with 'withReadOnlyStyle'"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ `
+ import { TextField } from "other-library";
+
+ `,
+ `
+ import { TextField } from "other-library";
+
+ `,
+ "should not change when 'TextField' is not imported from vibe"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ `
+ import { OtherComponent as TextField } from "other-library";
+
+ `,
+ `
+ import { OtherComponent as TextField } from "other-library";
+
+ `,
+ "should not change when 'TextField' is an alias for another component that is not from vibe"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ `
+ import { OtherComponent as TextField } from "monday-ui-react-core";
+
+ `,
+ `
+ import { OtherComponent as TextField } from "monday-ui-react-core";
+
+ `,
+ "should not change when 'TextField' is an alias for another component from vibe"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ `
+ import { TextField as VibeComponent } from "monday-ui-react-core";
+
+ `,
+ `
+ import { TextField as VibeComponent } from "monday-ui-react-core";
+
+ `,
+ "should change when 'TextField' is imported with alias from vibe"
+ );
+ });
+
+ describe('remove "requiredAsterisk" if "required" prop is given', () => {
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should remove 'requiredAsterisk' prop when 'required' prop exists"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should not remove 'requiredAsterisk' when 'required' prop does not exist"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(`
+ <>
+
+
+ >
+ `),
+ prependImport(`
+ <>
+
+
+ >
+ `),
+ "should not remove 'requiredAsterisk' when 'required' prop is not present in the same component"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ prependImport(``),
+ prependImport(``),
+ "should remove 'requiredAsterisk' when 'required' exists with multiple other props"
+ );
+
+ defineInlineTest(
+ transform,
+ {},
+ ``,
+ ``,
+ "should not remove 'requiredAsterisk' when no import even if 'required' prop exists"
+ );
+ });
+});
diff --git a/packages/codemod/transformations/core/v2-to-v3/text-field-component-migration.ts b/packages/codemod/transformations/core/v2-to-v3/text-field-component-migration.ts
new file mode 100644
index 0000000000..74aa0204e5
--- /dev/null
+++ b/packages/codemod/transformations/core/v2-to-v3/text-field-component-migration.ts
@@ -0,0 +1,34 @@
+import {
+ wrap,
+ getCoreImportsForFile,
+ getComponentNameOrAliasFromImports,
+ findComponentElements,
+ migratePropsNames,
+ removeProp,
+ isPropExists
+} from "../../../src/utils";
+import { TransformationContext } from "../../../types";
+
+/**
+ * 1. Change the 'dataTestId' prop to 'data-testid'
+ * 2. Remove 'withReadOnlyStyle' prop
+ * 3. Remove 'requiredAsterisk' prop if 'required' prop exists
+ */
+function transform({ j, root, filePath }: TransformationContext) {
+ const imports = getCoreImportsForFile(root);
+ const componentName = getComponentNameOrAliasFromImports(j, imports, "TextField");
+ if (!componentName) return;
+
+ const elements = findComponentElements(root, componentName);
+ if (!elements.length) return;
+
+ elements.forEach(elementPath => {
+ migratePropsNames(j, elementPath, filePath, componentName, { dataTestId: "data-testid" });
+ removeProp(j, elementPath, "withReadOnlyStyle");
+ if (isPropExists(j, elementPath, "required")) {
+ removeProp(j, elementPath, "requiredAsterisk");
+ }
+ });
+}
+
+export default wrap(transform);
diff --git a/packages/core/docs/vibe-3-changelog.md b/packages/core/docs/vibe-3-changelog.md
index cdf9ce4e08..df7a71930a 100644
--- a/packages/core/docs/vibe-3-changelog.md
+++ b/packages/core/docs/vibe-3-changelog.md
@@ -282,13 +282,12 @@ codemod: `tab-panels-import-migration`
### TextField
-- `dataTestId` -> `data-testid` [codemod]
-- `iconsNames` prop removed `layout` [codemod]
+- `dataTestId` -> `data-testid` [codemod ✅]
+- `iconsNames` prop removed `layout`
- Behavior of asterisk is now controlled by `required` prop, which means a field with asterisk will have to be required.
- - Removed `requiredAsterisk` [codemod] (codemod should replace only if `requiredAsterisk` is used with `required`)
-- Remove `withReadOnlyStyle` prop, new read only style will apply when using `readOnly` prop [codemod - remove withReadOnlyStyle]
+ - Removed `requiredAsterisk` [codemod ✅]
+- Remove `withReadOnlyStyle` prop, new read only style will apply when using `readOnly` prop [codemod ✅]
- Removed `sm`, `md`, `lg` sizes, use `small`, `medium`, `large` respectively
--
### ThemeProvider