Skip to content

feat(core/date-input): dime input validation improvements#2543

Open
RamVinayMandal wants to merge 47 commits into
siemens:mainfrom
RamVinayMandal:fix-ix-3322-display-input-as-valid-when-value-is-empty-for-date
Open

feat(core/date-input): dime input validation improvements#2543
RamVinayMandal wants to merge 47 commits into
siemens:mainfrom
RamVinayMandal:fix-ix-3322-display-input-as-valid-when-value-is-empty-for-date

Conversation

@RamVinayMandal

@RamVinayMandal RamVinayMandal commented May 11, 2026

Copy link
Copy Markdown
Collaborator

💡 What is the current behavior?

  • Non-required ix-date-input shows as invalid when cleared, even though empty should be valid
  • Required ix-date-input doesn't consistently show as invalid when the value is removed
  • novalidate forms still display visual validation feedback despite opting out of validation
  • Validation state doesn't update immediately when toggling the required attribute

JIRA: IX-2595 IX-3322

🆕 What is the new behavior?

Validation Fixes

  • Non-required, empty value: Now correctly validates as valid (no is-invalid class)
  • Required, empty value: Shows required-missing error only after user interaction (blur) or reportValidity()
  • novalidate forms: Suppress all visual validation feedback; reportValidity() overrides this suppression
  • Dynamic required attribute: Validation state updates immediately when toggling
  • Form submission is now prevented when the field is invalid or required but empty; submission proceeds only when the field is valid (form-associated component with ElementInternals validation).

New APIs

  • Added clear() method to clear value and validation state (removes touched flag and error classes)
  • Added reportValidity() method to trigger validation and show errors immediately
  • Added i18nErrorRequired prop to customize the required-field error message

Validation Behavior

  • Internal validation runs for all value sources (keyboard, programmatic, calendar picker)
  • Visual errors appear only after first user interaction; programmatic changes validate internally without visual feedback
  • novalidate suppression is overridden by reportValidity() to show errors

Additional Improvements

  • Clicking and holding calendar dates does not trigger validation errors on required empty fields; removed momentary red-border flash when selecting a calendar date
  • Fixed min/max date bounds operators

Note: The clear(), reportValidity() methods and i18nErrorRequired prop on ix-date-input is tagged with @since 5.2.0. Please verify this matches the actual target release version and we need to update the JSDoc tag if needed before merging.

🏁 Checklist

A pull request can only be merged if all of these conditions are met (where applicable):

  • 🦮 Accessibility (a11y) features were implemented
  • 🗺️ Internationalization (i18n) - no hard coded strings
  • 📲 Responsiveness - components handle viewport changes and content overflow gracefully
  • 📕 Add or update a Storybook story
  • 📄 Documentation was reviewed/updated siemens/ix-docs
  • 🧪 Unit tests were added/updated and pass (pnpm test)
  • 📸 Visual regression tests were added/updated and pass (Guide)
  • 🧐 Static code analysis passes (pnpm lint)
  • 🏗️ Successful compilation (pnpm build, changes pushed)

Summary by CodeRabbit

Summary by CodeRabbit

Summary

  • New Features

    • Added clear() and reportValidity() to ix-date-input, plus i18nErrorRequired to customize required-field messaging.
    • Exposed the new APIs/prop in Angular, React, and Vue wrappers.
  • Bug Fixes

    • Improved required vs optional empty validation, visual-error timing, and required-message updates after corrections (including calendar/picker interactions).
    • Enhanced novalidate and form submission behavior to block/allow submit based on validation.
  • Tests

    • Expanded Playwright regression and accessibility coverage for validation visuals and form submission.

… state

Co-authored-by: Copilot <copilot@github.com>
@changeset-bot

changeset-bot Bot commented May 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1c36671

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 5 packages
Name Type
@siemens/ix Minor
@siemens/ix-angular Minor
@siemens/ix-docs Minor
@siemens/ix-react Minor
@siemens/ix-vue Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a clear() method to the ix-date-input component and refines its validation logic to better handle novalidate forms and programmatic value resets. The changes include a new utility for clearing inputs and extensive regression tests. Review feedback suggests that date parsing should still be performed even when visual validation is suppressed to avoid invalid internal states. Furthermore, the reviewer recommends explicitly synchronizing validation classes during programmatic clears and ensuring that asynchronous validation calls are correctly awaited in property watchers.

Comment thread packages/core/src/components/date-input/date-input.tsx
Comment thread packages/core/src/components/date-input/date-input.tsx Outdated
Comment thread packages/core/src/components/date-input/date-input.tsx Outdated
@RamVinayMandal RamVinayMandal self-assigned this May 12, 2026
@RamVinayMandal

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a clear() method to the ix-date-input component and refactors its validation logic to correctly handle novalidate forms and programmatic value resets. The changes include adding a syncValidationClasses method, updating the value watcher, and providing comprehensive regression tests. Feedback focuses on ensuring that asynchronous validation methods are properly awaited, stale validation classes are removed when validation is suppressed (e.g., in novalidate forms), and that accessibility coverage is maintained with an axe-based component test as per the repository style guide.

Comment thread packages/core/src/components/date-input/date-input.tsx
Comment thread packages/core/src/components/date-input/date-input.tsx Outdated
Comment thread packages/core/src/components/date-input/tests/date-input.ct.ts
Comment thread packages/core/src/components/input/input.util.ts
- Introduced a new `reportValidity` method to explicitly trigger validation and surface errors immediately, regardless of user interaction.
- Updated validation logic to ensure required fields show appropriate error messages when empty.
- Improved internal state management for invalid inputs, ensuring visual feedback aligns with user interactions.
- Refactored validation classes and error messaging to provide clearer user feedback, including handling of required fields and parse errors.
- Added tests to cover new validation scenarios, including behavior in `novalidate` forms and programmatic value changes.
@netlify

netlify Bot commented Jun 3, 2026

Copy link
Copy Markdown

Deploy Preview for ix-storybook ready!

Name Link
🔨 Latest commit 1c36671
🔍 Latest deploy log https://app.netlify.com/projects/ix-storybook/deploys/6a43fdb55d6dfc000972af80
😎 Deploy Preview https://deploy-preview-2543--ix-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

…sistency

- Moved and restructured tests related to initial invalid values and user interactions.
- Consolidated required and optional field behavior tests for better readability.
- Enhanced test descriptions for improved understanding of scenarios.
- Ensured consistent handling of visual validation states across tests.
…e-is-empty-for-date

# Conflicts:
#	packages/core/src/components/date-input/date-input.tsx
#	packages/react/src/components.server.ts
#	packages/vue/src/components.ts
@RamVinayMandal

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant validation improvements to the ix-date-input component, including new clear() and reportValidity() methods, a customizable i18nErrorRequired property, and proper validation suppression within novalidate forms. The feedback highlights a potential runtime crash in Luxon when minDate or maxDate is undefined, suggesting safe guards in getDateValidation. Additionally, the reviewer notes that when enableTopLayer is active, focus transitions to the dropdown are incorrectly treated as external, and recommends passing the dropdown element reference to handlePickerInputBlur and handlePickerHostFocusout to prevent premature validation and closure.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/core/src/components/date-input/date-input.tsx
Comment thread packages/core/src/components/utils/input/picker-input.util.ts Outdated
Comment thread packages/core/src/components/date-input/date-input.tsx
Comment thread packages/core/src/components/date-input/date-input.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/core/src/components/date-input/date-input.tsx (2)

307-308: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset validityTracker when clear() returns the control to pristine.

emitPickerValidityStateChangeIfChanged() memoizes the last emitted patternMismatch/valueMissing pair. clear() removes touched/visual state, but it leaves that cache intact, so re-entering the same invalid state after a clear is filtered as “unchanged” and validityStateChange no longer fires.

Suggested fix
   async clear(): Promise<void> {
     this._hasInvalidInput = false;
     this._reportValidityCalled = false;
+    this.validityTracker = createPickerValidityStateTracker();
     await clearInputValue(this, {
       defaultValue: '',
       additionalCleanup: () => {
         this.from = undefined;
       },

Also applies to: 390-399

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 307 -
308, The cached validity state in validityTracker (created by
createPickerValidityStateTracker()) must be reset when clear() returns the
control to pristine so emitPickerValidityStateChangeIfChanged() won't suppress
future identical invalid states; update the clear() implementation(s) to
reinitialize the tracker (e.g., assign a new createPickerValidityStateTracker()
or call a reset method on validityTracker) after you remove touched/visual
state, and apply the same change to the other clear-like code path referenced in
the file (the other clear/restore block that uses
emitPickerValidityStateChangeIfChanged/validityTracker).

817-823: ⚠️ Potential issue | 🔴 Critical

Bind handlePickerFocusoutCallback before passing it into handlePickerFocusoutWithValidation

handlePickerFocusoutWithValidation() calls the provided callback as a plain function (onValidateAndBlur(...)). Passing this.handlePickerFocusoutCallback directly drops the component instance, so this inside handlePickerFocusoutCallback can be undefined while it uses this.closeDropdown(), this.touched, etc.

Suggested fix
         onFocusout={(e: FocusEvent) =>
           handlePickerFocusoutWithValidation(
             e,
             this.hostElement,
-            this.handlePickerFocusoutCallback,
+            (hasRelatedTarget) =>
+              this.handlePickerFocusoutCallback(hasRelatedTarget),
             this.dropdownElementRef?.current
           )
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 817 -
823, The passed callback this.handlePickerFocusoutCallback loses its instance
context when invoked inside handlePickerFocusoutWithValidation; update the
onFocusout call to pass a bound function so that inside
handlePickerFocusoutCallback methods like this.closeDropdown() and properties
like this.touched work correctly — e.g., bind the method to the component
instance (this.handlePickerFocusoutCallback.bind(this)) or wrap it in an arrow
that calls this.handlePickerFocusoutCallback(...); keep using
handlePickerFocusoutWithValidation, hostElement and dropdownElementRef as the
other arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 307-308: The cached validity state in validityTracker (created by
createPickerValidityStateTracker()) must be reset when clear() returns the
control to pristine so emitPickerValidityStateChangeIfChanged() won't suppress
future identical invalid states; update the clear() implementation(s) to
reinitialize the tracker (e.g., assign a new createPickerValidityStateTracker()
or call a reset method on validityTracker) after you remove touched/visual
state, and apply the same change to the other clear-like code path referenced in
the file (the other clear/restore block that uses
emitPickerValidityStateChangeIfChanged/validityTracker).
- Around line 817-823: The passed callback this.handlePickerFocusoutCallback
loses its instance context when invoked inside
handlePickerFocusoutWithValidation; update the onFocusout call to pass a bound
function so that inside handlePickerFocusoutCallback methods like
this.closeDropdown() and properties like this.touched work correctly — e.g.,
bind the method to the component instance
(this.handlePickerFocusoutCallback.bind(this)) or wrap it in an arrow that calls
this.handlePickerFocusoutCallback(...); keep using
handlePickerFocusoutWithValidation, hostElement and dropdownElementRef as the
other arguments.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: edfd2e0d-57b8-4ec1-ba39-2e5d47826a5c

📥 Commits

Reviewing files that changed from the base of the PR and between 6d83c6c and e626b83.

📒 Files selected for processing (3)
  • packages/core/src/components/date-input/date-input.tsx
  • packages/core/src/components/input/input.util.ts
  • packages/core/src/components/utils/input/picker-input.util.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/core/src/components/date-input/date-input.tsx (3)

142-146: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Emit validityStateChange when required changes.

Line 145 resynchronizes CSS and ElementInternals, but onRequiredChange() never emits validityStateChange. Toggling required on an empty field changes the component’s public validity state without notifying listeners of the change.

Suggested fix
 `@Watch`('required')
 async onRequiredChange() {
   await syncRequiredValidationClass(this.hostElement, this);
   this.syncFormInternalsValidity();
+  emitPickerValidityState(this);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 142 -
146, The onRequiredChange() watcher updates CSS and ElementInternals but doesn't
notify listeners; after calling syncRequiredValidationClass(this.hostElement,
this) and this.syncFormInternalsValidity() inside onRequiredChange(), dispatch
or emit the component's validityStateChange event (or call the existing
emitter/dispatcher for validityStateChange) so consumers are notified when the
required attribute toggles; update the onRequiredChange() implementation in the
DateInput component to emit validityStateChange after
syncFormInternalsValidity() using the same event name/signature used elsewhere
in the component.

727-733: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

reportValidity() still leaves pristine required-empty fields without public error state.

These branches still derive required-empty state from touched only. After reportValidity() on a pristine required field, the component can show the required CSS path via _reportValidityCalled, but getValidityState() still reports valid and getInvalidText() still returns nothing. That breaks the new contract described in the PR: required-missing feedback should surface when reportValidity() is called.

Suggested fix
+private shouldShowRequiredState(): boolean {
+  return !!this.required && (this.touched || this._reportValidityCalled);
+}
+
 /** `@internal` */
 `@Method`()
 getValidityState(): Promise<ValidityState> {
   return Promise.resolve(
     createValidityState(
       this.isInputInvalid,
-      !!this.required && this.touched,
+      this.shouldShowRequiredState(),
       this.value
     )
   );
 }
 ...
 private getInvalidText(): string | undefined {
-  const isRequiredEmpty = !!this.required && !this.value && this.touched;
+  const isRequiredEmpty = this.shouldShowRequiredState() && !this.value;

Also applies to: 788-802

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 727 -
733, getValidityState currently derives the required-empty condition from
this.touched only, so calling reportValidity() doesn't flip public validity;
update the required-missing logic in getValidityState (the Promise.resolve call
around createValidityState) to treat required as missing when this.required &&
(this.touched || this._reportValidityCalled) rather than using this.touched
alone, and make the same change in the corresponding getInvalidText branch (the
block around lines 788-802) so both methods honor _reportValidityCalled when
reportValidity() has been invoked.

344-355: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid firing valueChange during initial state sync.

Line 345 now routes componentWillLoad() through onInput(), but both downstream paths (handleEmptyInput() and handleValidatedInput()) emit valueChange. That publishes a change event during first render even when the consumer only supplied the initial prop value, which violates the event contract at Line 260 and can trigger phantom updates in two-way bindings.

Suggested direction
 override async componentWillLoad(): Promise<void> {
-  await this.onInput(this.value);
+  await this.onInput(this.value, { emitValueChange: false });
   if (this._hasInvalidInput) {
     this.from = null;
   } else {
     this.watchValue();
   }
-async onInput(value: string | undefined) {
+async onInput(
+  value: string | undefined,
+  options: { emitValueChange?: boolean } = {}
+) {
   this.value = value;
   if (!value) {
-    await this.handleEmptyInput(value);
+    await this.handleEmptyInput(value, options);
     return;
   }
   ...
-  await this.handleValidatedInput(value);
+  await this.handleValidatedInput(value, options);
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 344 -
355, componentWillLoad currently calls onInput(this.value) which propagates
through handleEmptyInput/handleValidatedInput and emits the valueChange event
during initial render; change componentWillLoad to perform initial
parsing/validation without emitting valueChange (e.g., call internal parsing
helpers or add a flag to onInput like suppressEvent=true) so that
handleEmptyInput and handleValidatedInput skip emitting valueChange during
initial sync; update componentWillLoad to then call watchValue(),
checkClassList(), updateFormInternalValue, and syncFormInternalsValidity as
before, ensuring valueChange only fires on user-driven updates; reference
componentWillLoad, onInput, handleEmptyInput, handleValidatedInput, and
valueChange when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 142-146: The onRequiredChange() watcher updates CSS and
ElementInternals but doesn't notify listeners; after calling
syncRequiredValidationClass(this.hostElement, this) and
this.syncFormInternalsValidity() inside onRequiredChange(), dispatch or emit the
component's validityStateChange event (or call the existing emitter/dispatcher
for validityStateChange) so consumers are notified when the required attribute
toggles; update the onRequiredChange() implementation in the DateInput component
to emit validityStateChange after syncFormInternalsValidity() using the same
event name/signature used elsewhere in the component.
- Around line 727-733: getValidityState currently derives the required-empty
condition from this.touched only, so calling reportValidity() doesn't flip
public validity; update the required-missing logic in getValidityState (the
Promise.resolve call around createValidityState) to treat required as missing
when this.required && (this.touched || this._reportValidityCalled) rather than
using this.touched alone, and make the same change in the corresponding
getInvalidText branch (the block around lines 788-802) so both methods honor
_reportValidityCalled when reportValidity() has been invoked.
- Around line 344-355: componentWillLoad currently calls onInput(this.value)
which propagates through handleEmptyInput/handleValidatedInput and emits the
valueChange event during initial render; change componentWillLoad to perform
initial parsing/validation without emitting valueChange (e.g., call internal
parsing helpers or add a flag to onInput like suppressEvent=true) so that
handleEmptyInput and handleValidatedInput skip emitting valueChange during
initial sync; update componentWillLoad to then call watchValue(),
checkClassList(), updateFormInternalValue, and syncFormInternalsValidity as
before, ensuring valueChange only fires on user-driven updates; reference
componentWillLoad, onInput, handleEmptyInput, handleValidatedInput, and
valueChange when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5b327045-511b-482a-a72a-09bd94137fec

📥 Commits

Reviewing files that changed from the base of the PR and between e626b83 and 5888100.

📒 Files selected for processing (1)
  • packages/core/src/components/date-input/date-input.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/components/date-input/date-input.tsx (1)

607-626: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Extract duplicated blur/focusout validation logic into a shared method.

The validation logic in handlePickerFocusoutCallback (lines 619-625) and the onBlur callback (lines 672-682) is nearly identical:

this.touched = true;
const suppress = await shouldSuppressInternalValidation(this);
if (!suppress) {
  this.isInputInvalid = this._hasInvalidInput;
}
onInputBlurWithChange(this, this.inputElementRef.current, this.value);
emitPickerValidityState(this);

Consider extracting this to a private method to reduce duplication and simplify future maintenance.

♻️ Proposed refactor
+  private async runBlurValidation(): Promise<void> {
+    this.touched = true;
+    const suppress = await shouldSuppressInternalValidation(this);
+    if (!suppress) {
+      this.isInputInvalid = this._hasInvalidInput;
+    }
+    onInputBlurWithChange(this, this.inputElementRef.current, this.value);
+    emitPickerValidityState(this);
+  }
+
   private readonly handlePickerFocusoutCallback = async (
     hasRelatedTarget: boolean
   ) => {
     if (hasRelatedTarget) {
       this.closeDropdown();
     }
 
     if (this._shouldSkipFocusoutValidation) {
       this._shouldSkipFocusoutValidation = false;
       return;
     }
 
-    this.touched = true;
-    const suppress = await shouldSuppressInternalValidation(this);
-    if (!suppress) {
-      this.isInputInvalid = this._hasInvalidInput;
-    }
-    onInputBlurWithChange(this, this.inputElementRef.current, this.value);
-    emitPickerValidityState(this);
+    await this.runBlurValidation();
   };

Then in the onBlur callback:

           onBlur={(e: FocusEvent) =>
             suppressInputBlurWhenFocusMovedToPicker({
               event: e,
               isDropdownOpen: this.show,
               hostElement: this.hostElement,
               onBlur: async () => {
-                this.touched = true;
-                const suppress = await shouldSuppressInternalValidation(this);
-                if (!suppress) {
-                  this.isInputInvalid = this._hasInvalidInput;
-                }
-                onInputBlurWithChange(
-                  this,
-                  this.inputElementRef.current,
-                  this.value
-                );
-                emitPickerValidityState(this);
+                await this.runBlurValidation();
                 this._shouldSkipFocusoutValidation = true;
               },
               pickerElement: this.dropdownElementRef?.current,
             })
           }

Also applies to: 666-687

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 607 -
626, The validation logic in the handlePickerFocusoutCallback method (lines
619-625) is duplicated in the onBlur callback (around lines 672-682). Extract
this common validation sequence (which includes setting touched to true, calling
shouldSuppressInternalValidation, conditionally setting isInputInvalid, and
calling onInputBlurWithChange and emitPickerValidityState) into a new private
async method. Then replace both instances of the duplicated code with calls to
this new shared method to reduce duplication and improve maintainability.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 607-626: The validation logic in the handlePickerFocusoutCallback
method (lines 619-625) is duplicated in the onBlur callback (around lines
672-682). Extract this common validation sequence (which includes setting
touched to true, calling shouldSuppressInternalValidation, conditionally setting
isInputInvalid, and calling onInputBlurWithChange and emitPickerValidityState)
into a new private async method. Then replace both instances of the duplicated
code with calls to this new shared method to reduce duplication and improve
maintainability.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: fc1a05d0-3f83-463e-87c9-9e5b86380da2

📥 Commits

Reviewing files that changed from the base of the PR and between 5888100 and 7211df1.

📒 Files selected for processing (1)
  • packages/core/src/components/date-input/date-input.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.changeset/feat-date-input-validation.md (1)

1-20: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add issue linkage in the changeset summary (Fixes #<issue-number>).

The summary is missing the required issue-closing reference for release automation.

Suggested fix
 Added `i18nErrorRequired` prop (`i18n-error-required`) to customize the required-field error message.
+
+Fixes #<issue-number>

As per coding guidelines, "Include Fixes #<issue-number> syntax in changeset summary to automatically close linked GitHub issues when the changeset is released."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/feat-date-input-validation.md around lines 1 - 20, The changeset
file is missing the required issue-closing reference syntax. Add a "Fixes
#<issue-number>" line to the changeset summary section (after the package and
version type declaration and before or within the description) to enable
automatic GitHub issue closure when the changeset is released. Replace
<issue-number> with the actual GitHub issue number that this changeset
addresses.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 795-804: The onFocusout event handler is closing the dropdown
whenever focus moves to any element outside the input field, including internal
component elements like the picker. Instead of only checking if relatedTarget is
not null, add an additional check to verify that the relatedTarget is outside
the component itself by using contains() to check if this.el (the component's
root element) contains the relatedTarget. Only call this.closeDropdown() when
focus actually moves outside the component boundaries, not just when moving
between internal child elements like the input and picker.

In `@packages/core/src/components/date-input/tests/date-input.ct.ts`:
- Around line 397-404: After the mount(...) call that creates the ix-date-input
component, add a hydration assertion before any interactions occur. Insert an
await expect statement that checks if the dateInput locator has the hydrated
class using the regex pattern /\bhydrated\b/. This assertion should be placed
immediately after the dateInput variable assignment and before the click() call
to open-calendar, ensuring the component is fully hydrated before attempting to
interact with it and avoiding potential timing flakes.

---

Outside diff comments:
In @.changeset/feat-date-input-validation.md:
- Around line 1-20: The changeset file is missing the required issue-closing
reference syntax. Add a "Fixes #<issue-number>" line to the changeset summary
section (after the package and version type declaration and before or within the
description) to enable automatic GitHub issue closure when the changeset is
released. Replace <issue-number> with the actual GitHub issue number that this
changeset addresses.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6635ad04-c22a-4c03-bb89-472d07f83ed1

📥 Commits

Reviewing files that changed from the base of the PR and between 7211df1 and 086f9f5.

📒 Files selected for processing (4)
  • .changeset/feat-date-input-validation.md
  • packages/core/src/components/date-input/date-input.tsx
  • packages/core/src/components/date-input/tests/date-input.ct.ts
  • packages/core/src/components/utils/input/picker-input.util.ts
💤 Files with no reviewable changes (1)
  • packages/core/src/components/utils/input/picker-input.util.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.changeset/feat-date-input-validation.md (1)

1-20: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add issue linkage in the changeset summary (Fixes #<issue-number>).

The summary is missing the required issue-closing reference for release automation.

Suggested fix
 Added `i18nErrorRequired` prop (`i18n-error-required`) to customize the required-field error message.
+
+Fixes #<issue-number>

As per coding guidelines, "Include Fixes #<issue-number> syntax in changeset summary to automatically close linked GitHub issues when the changeset is released."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/feat-date-input-validation.md around lines 1 - 20, The changeset
file is missing the required issue-closing reference syntax. Add a "Fixes
#<issue-number>" line to the changeset summary section (after the package and
version type declaration and before or within the description) to enable
automatic GitHub issue closure when the changeset is released. Replace
<issue-number> with the actual GitHub issue number that this changeset
addresses.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 795-804: The onFocusout event handler is closing the dropdown
whenever focus moves to any element outside the input field, including internal
component elements like the picker. Instead of only checking if relatedTarget is
not null, add an additional check to verify that the relatedTarget is outside
the component itself by using contains() to check if this.el (the component's
root element) contains the relatedTarget. Only call this.closeDropdown() when
focus actually moves outside the component boundaries, not just when moving
between internal child elements like the input and picker.

In `@packages/core/src/components/date-input/tests/date-input.ct.ts`:
- Around line 397-404: After the mount(...) call that creates the ix-date-input
component, add a hydration assertion before any interactions occur. Insert an
await expect statement that checks if the dateInput locator has the hydrated
class using the regex pattern /\bhydrated\b/. This assertion should be placed
immediately after the dateInput variable assignment and before the click() call
to open-calendar, ensuring the component is fully hydrated before attempting to
interact with it and avoiding potential timing flakes.

---

Outside diff comments:
In @.changeset/feat-date-input-validation.md:
- Around line 1-20: The changeset file is missing the required issue-closing
reference syntax. Add a "Fixes #<issue-number>" line to the changeset summary
section (after the package and version type declaration and before or within the
description) to enable automatic GitHub issue closure when the changeset is
released. Replace <issue-number> with the actual GitHub issue number that this
changeset addresses.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6635ad04-c22a-4c03-bb89-472d07f83ed1

📥 Commits

Reviewing files that changed from the base of the PR and between 7211df1 and 086f9f5.

📒 Files selected for processing (4)
  • .changeset/feat-date-input-validation.md
  • packages/core/src/components/date-input/date-input.tsx
  • packages/core/src/components/date-input/tests/date-input.ct.ts
  • packages/core/src/components/utils/input/picker-input.util.ts
💤 Files with no reviewable changes (1)
  • packages/core/src/components/utils/input/picker-input.util.ts
🛑 Comments failed to post (2)
packages/core/src/components/date-input/date-input.tsx (1)

795-804: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Dropdown is closed on internal focus moves, which can break picker interactions.

Line 803 closes the dropdown for any non-null relatedTarget. On focusout, that includes focus transitions within the component (input → picker/dropdown), so the picker can close mid-interaction.

Suggested fix
-        onFocusout={(e: FocusEvent) => {
-          const relatedTarget = e.relatedTarget as Node;
-
-          // Related target might be null during rerenders, which would cause the dropdown to close unexpectedly
-          if (!relatedTarget) {
-            return;
-          }
-
-          this.closeDropdown();
-        }}
+        onFocusout={(e: FocusEvent) => {
+          const relatedTarget = e.relatedTarget as Node | null;
+
+          // Related target might be null during rerenders
+          if (!relatedTarget) {
+            return;
+          }
+
+          // Keep dropdown open while focus stays within this component/picker
+          if (this.hostElement.contains(relatedTarget)) {
+            return;
+          }
+
+          this.closeDropdown();
+        }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        onFocusout={(e: FocusEvent) => {
          const relatedTarget = e.relatedTarget as Node | null;

          // Related target might be null during rerenders
          if (!relatedTarget) {
            return;
          }

          // Keep dropdown open while focus stays within this component/picker
          if (this.hostElement.contains(relatedTarget)) {
            return;
          }

          this.closeDropdown();
        }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 795 -
804, The onFocusout event handler is closing the dropdown whenever focus moves
to any element outside the input field, including internal component elements
like the picker. Instead of only checking if relatedTarget is not null, add an
additional check to verify that the relatedTarget is outside the component
itself by using contains() to check if this.el (the component's root element)
contains the relatedTarget. Only call this.closeDropdown() when focus actually
moves outside the component boundaries, not just when moving between internal
child elements like the input and picker.
packages/core/src/components/date-input/tests/date-input.ct.ts (1)

397-404: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add hydration assertion before interacting with the mounted component.

This test starts interactions immediately after mount(...). Add the required hydration assertion first to avoid timing flakes.

Suggested fix
       await mount(`<ix-date-input required value=""></ix-date-input>`);

       const dateInput = page.locator('ix-date-input');
+      await expect(dateInput).toHaveClass(/\bhydrated\b/);
       const input = dateInput.getByRole('textbox');

       await dateInput.getByTestId('open-calendar').click();

As per coding guidelines, "Always verify components are hydrated before making further assertions using await expect(page.locator('ix-component')).toHaveClass(/\bhydrated\b/)."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

      await mount(`<ix-date-input required value=""></ix-date-input>`);

      const dateInput = page.locator('ix-date-input');
      await expect(dateInput).toHaveClass(/\bhydrated\b/);
      const input = dateInput.getByRole('textbox');

      await dateInput.getByTestId('open-calendar').click();
      await expect(dateInput.getByTestId('date-dropdown')).toHaveClass(/show/);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/tests/date-input.ct.ts` around lines
397 - 404, After the mount(...) call that creates the ix-date-input component,
add a hydration assertion before any interactions occur. Insert an await expect
statement that checks if the dateInput locator has the hydrated class using the
regex pattern /\bhydrated\b/. This assertion should be placed immediately after
the dateInput variable assignment and before the click() call to open-calendar,
ensuring the component is fully hydrated before attempting to interact with it
and avoiding potential timing flakes.

Source: Coding guidelines

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.changeset/feat-date-input-validation.md (1)

5-21: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add Fixes #<issue-number> to this changeset summary.

The summary is missing the required issue-closing reference line. Please include the linked issue in Fixes #1234`` format.

As per coding guidelines, “Include Fixes #<issue-number> syntax in changeset summary to automatically close linked GitHub issues when the changeset is released.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/feat-date-input-validation.md around lines 5 - 21, The changeset
summary in feat-date-input-validation.md is missing the required issue-closing
reference line. Add a new line to the changeset summary that includes the `Fixes
#<issue-number>` syntax (replacing issue-number with the actual GitHub issue
number this changeset addresses) to ensure the linked issue is automatically
closed when the changeset is released. This line should be included somewhere in
the changeset content, typically at the beginning or end of the summary section.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 796-805: The onFocusout handler is closing the dropdown whenever
relatedTarget is non-null, but this also triggers when focus moves to internal
elements within the date-input/picker component itself. Modify the condition to
check whether the relatedTarget is actually outside the component before calling
closeDropdown(). You should verify that the relatedTarget is not a descendant of
the date-input component (or the component itself) before closing the dropdown,
allowing internal focus transitions to proceed without interrupting
keyboard/calendar interactions.

In `@packages/core/src/components/date-input/tests/date-input.ct.ts`:
- Around line 411-417: Add hydration verification before performing interactions
in the test blocks. After mounting the ix-date-input component, insert an
assertion to verify that the component has the hydrated class using the pattern
`await expect(page.locator('ix-date-input')).toHaveClass(/\bhydrated\b/)` before
calling any interaction methods like click() or type(). Apply this hydration
assertion to all the new test blocks mentioned in the additional ranges to
prevent racey test failures.

---

Outside diff comments:
In @.changeset/feat-date-input-validation.md:
- Around line 5-21: The changeset summary in feat-date-input-validation.md is
missing the required issue-closing reference line. Add a new line to the
changeset summary that includes the `Fixes #<issue-number>` syntax (replacing
issue-number with the actual GitHub issue number this changeset addresses) to
ensure the linked issue is automatically closed when the changeset is released.
This line should be included somewhere in the changeset content, typically at
the beginning or end of the summary section.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a9579f5a-614a-4f9c-8939-558f93e8a8bb

📥 Commits

Reviewing files that changed from the base of the PR and between 7211df1 and e531f5d.

📒 Files selected for processing (5)
  • .changeset/feat-date-input-validation.md
  • packages/core/src/components/date-input/date-input.tsx
  • packages/core/src/components/date-input/tests/date-input.ct.ts
  • packages/core/src/components/input/tests/form-ready.ct.ts
  • packages/core/src/components/utils/input/picker-input.util.ts
💤 Files with no reviewable changes (1)
  • packages/core/src/components/utils/input/picker-input.util.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.changeset/feat-date-input-validation.md (1)

5-21: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add Fixes #<issue-number> to this changeset summary.

The summary is missing the required issue-closing reference line. Please include the linked issue in Fixes #1234`` format.

As per coding guidelines, “Include Fixes #<issue-number> syntax in changeset summary to automatically close linked GitHub issues when the changeset is released.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.changeset/feat-date-input-validation.md around lines 5 - 21, The changeset
summary in feat-date-input-validation.md is missing the required issue-closing
reference line. Add a new line to the changeset summary that includes the `Fixes
#<issue-number>` syntax (replacing issue-number with the actual GitHub issue
number this changeset addresses) to ensure the linked issue is automatically
closed when the changeset is released. This line should be included somewhere in
the changeset content, typically at the beginning or end of the summary section.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 796-805: The onFocusout handler is closing the dropdown whenever
relatedTarget is non-null, but this also triggers when focus moves to internal
elements within the date-input/picker component itself. Modify the condition to
check whether the relatedTarget is actually outside the component before calling
closeDropdown(). You should verify that the relatedTarget is not a descendant of
the date-input component (or the component itself) before closing the dropdown,
allowing internal focus transitions to proceed without interrupting
keyboard/calendar interactions.

In `@packages/core/src/components/date-input/tests/date-input.ct.ts`:
- Around line 411-417: Add hydration verification before performing interactions
in the test blocks. After mounting the ix-date-input component, insert an
assertion to verify that the component has the hydrated class using the pattern
`await expect(page.locator('ix-date-input')).toHaveClass(/\bhydrated\b/)` before
calling any interaction methods like click() or type(). Apply this hydration
assertion to all the new test blocks mentioned in the additional ranges to
prevent racey test failures.

---

Outside diff comments:
In @.changeset/feat-date-input-validation.md:
- Around line 5-21: The changeset summary in feat-date-input-validation.md is
missing the required issue-closing reference line. Add a new line to the
changeset summary that includes the `Fixes #<issue-number>` syntax (replacing
issue-number with the actual GitHub issue number this changeset addresses) to
ensure the linked issue is automatically closed when the changeset is released.
This line should be included somewhere in the changeset content, typically at
the beginning or end of the summary section.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a9579f5a-614a-4f9c-8939-558f93e8a8bb

📥 Commits

Reviewing files that changed from the base of the PR and between 7211df1 and e531f5d.

📒 Files selected for processing (5)
  • .changeset/feat-date-input-validation.md
  • packages/core/src/components/date-input/date-input.tsx
  • packages/core/src/components/date-input/tests/date-input.ct.ts
  • packages/core/src/components/input/tests/form-ready.ct.ts
  • packages/core/src/components/utils/input/picker-input.util.ts
💤 Files with no reviewable changes (1)
  • packages/core/src/components/utils/input/picker-input.util.ts
🛑 Comments failed to post (2)
packages/core/src/components/date-input/date-input.tsx (1)

796-805: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Avoid closing the dropdown on internal focus moves.

Line 804 closes the dropdown for any non-null relatedTarget. That also catches focus transitions inside the date-input/picker, which can interrupt keyboard/calendar interaction.

Suggested fix
         onFocusout={(e: FocusEvent) => {
-          const relatedTarget = e.relatedTarget as Node;
+          const relatedTarget = e.relatedTarget as Node | null;
 
           // Related target might be null during rerenders, which would cause the dropdown to close unexpectedly
           if (!relatedTarget) {
             return;
           }
 
+          const movedInsideHost = this.hostElement.contains(relatedTarget);
+          const movedInsidePicker =
+            this.dropdownElementRef.current?.contains(relatedTarget) ?? false;
+
+          if (movedInsideHost || movedInsidePicker) {
+            return;
+          }
+
           this.closeDropdown();
         }}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 796 -
805, The onFocusout handler is closing the dropdown whenever relatedTarget is
non-null, but this also triggers when focus moves to internal elements within
the date-input/picker component itself. Modify the condition to check whether
the relatedTarget is actually outside the component before calling
closeDropdown(). You should verify that the relatedTarget is not a descendant of
the date-input component (or the component itself) before closing the dropdown,
allowing internal focus transitions to proceed without interrupting
keyboard/calendar interactions.
packages/core/src/components/date-input/tests/date-input.ct.ts (1)

411-417: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add hydration assertions before interactions in the new tests.

These new tests click/type immediately after mount. Please assert hydration first to avoid racey failures.

Suggested pattern (apply to each new test block)
       const dateInput = page.locator('ix-date-input');
+      await expect(dateInput).toHaveClass(/\bhydrated\b/);
       await page.locator('button[type="submit"]').click();

As per coding guidelines, “Always verify components are hydrated before making further assertions using await expect(page.locator('ix-component')).toHaveClass(/\bhydrated\b/)”.

Also applies to: 1027-1038, 1051-1063, 1076-1088

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/tests/date-input.ct.ts` around lines
411 - 417, Add hydration verification before performing interactions in the test
blocks. After mounting the ix-date-input component, insert an assertion to
verify that the component has the hydrated class using the pattern `await
expect(page.locator('ix-date-input')).toHaveClass(/\bhydrated\b/)` before
calling any interaction methods like click() or type(). Apply this hydration
assertion to all the new test blocks mentioned in the additional ranges to
prevent racey test failures.

Source: Coding guidelines

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/components/date-input/date-input.tsx (1)

206-212: 📐 Maintainability & Code Quality | 🟠 Major

Add Storybook stories for the new validation methods and error message customization.

The PR introduces user-visible APIs (i18nErrorRequired, clear(), reportValidity()) with proper @since 5.1.0 JSDoc tags and extensive component test coverage. However, the Storybook story at packages/storybook-docs/src/stories/input-date.stories.ts only demonstrates a basic required case and does not showcase these new validation features. Per path instructions, add story examples demonstrating the new methods and error message customization before merge.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 206 -
212, Add new Storybook story examples to the `input-date.stories.ts` file that
demonstrate the newly introduced validation features: the `i18nErrorRequired`
property for customizing the error message, the `clear()` method for clearing
the field, and the `reportValidity()` method for triggering validation. These
stories should showcase realistic usage patterns and clearly illustrate how
users can customize error messages and programmatically interact with validation
on the date input component.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 206-212: Add new Storybook story examples to the
`input-date.stories.ts` file that demonstrate the newly introduced validation
features: the `i18nErrorRequired` property for customizing the error message,
the `clear()` method for clearing the field, and the `reportValidity()` method
for triggering validation. These stories should showcase realistic usage
patterns and clearly illustrate how users can customize error messages and
programmatically interact with validation on the date input component.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 739906df-09c2-4cc8-b3b4-449e86110054

📥 Commits

Reviewing files that changed from the base of the PR and between e531f5d and 27c4cc8.

📒 Files selected for processing (1)
  • packages/core/src/components/date-input/date-input.tsx

@flxlst09 flxlst09 added this to the 5.2.0 milestone Jun 25, 2026
@RamVinayMandal RamVinayMandal changed the title feat(core/date-input): add clear method to reset value and validation… feat(core/date-input): dime input validation improvements Jun 29, 2026
…for-date' of github.com:RamVinayMandal/ix into fix-ix-3322-display-input-as-valid-when-value-is-empty-for-date
@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/components/date-input/date-input.tsx (1)

535-545: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep the form-associated value in sync for invalid edits.

This branch updates this.value and validity state, but it skips updateFormInternalValue(...). After a touched field becomes invalid, ElementInternals.setFormValue() can still hold the previous valid date, so FormData(form)/manual form serialization can read stale data instead of the current control state.

Suggested fix
     if (this._hasInvalidInput) {
       this.invalidReason = validation.invalidReason;
       this.from = undefined;
+      this.updateFormInternalValue(value);
     } else {
       this.invalidReason = undefined;
 
       await syncRequiredValidationClass(this.hostElement, this);
       this.updateFormInternalValue(value);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/components/date-input/date-input.tsx` around lines 535 -
545, The invalid-edit branch in date-input is leaving the form-associated value
stale because it updates validity state without refreshing the internal form
value. Update the invalid path in date-input.tsx so the same form sync logic
used in the valid path also runs after setting invalidReason and clearing from;
specifically, make sure updateFormInternalValue(...) is called from the branch
around this._hasInvalidInput so ElementInternals.setFormValue() stays aligned
with the current control state.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/core/src/components/date-input/date-input.tsx`:
- Around line 535-545: The invalid-edit branch in date-input is leaving the
form-associated value stale because it updates validity state without refreshing
the internal form value. Update the invalid path in date-input.tsx so the same
form sync logic used in the valid path also runs after setting invalidReason and
clearing from; specifically, make sure updateFormInternalValue(...) is called
from the branch around this._hasInvalidInput so ElementInternals.setFormValue()
stays aligned with the current control state.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7d4b72a6-3dba-42d1-8d67-ee9407cf4f76

📥 Commits

Reviewing files that changed from the base of the PR and between 4b8745a and 1c36671.

⛔ Files ignored due to path filters (2)
  • packages/angular/standalone/src/components.ts is excluded by !packages/angular/standalone/src/components.ts
  • packages/react/src/components/components.server.ts is excluded by !packages/react/src/components/**
📒 Files selected for processing (5)
  • packages/angular/src/components.ts
  • packages/core/src/components.d.ts
  • packages/core/src/components/date-input/date-input.tsx
  • packages/core/src/components/date-input/tests/date-input.ct.ts
  • packages/core/src/components/input/input.util.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants