diff --git a/BREAKING.md b/BREAKING.md
index 2ab8bb5226..c146937e11 100644
--- a/BREAKING.md
+++ b/BREAKING.md
@@ -123,7 +123,7 @@ This section details the desktop browser, JavaScript framework, and mobile platf
-- `ionChange` is no longer emitted when the `value` of `ion-input` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the input and the input losing focus or from clicking the clear action within the input.
+- `ionChange` is no longer emitted when the `value` of `ion-input` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the input and the input losing focus, clicking the clear action within the input, or pressing the "Enter" key.
- If your application requires immediate feedback based on the user typing actively in the input, consider migrating your event listeners to using `ionInput` instead.
@@ -196,7 +196,7 @@ Ionic now listens on the `keydown` event instead of the `keyup` event when deter
Searchbar
-- `ionChange` is no longer emitted when the `value` of `ion-searchbar` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the searchbar and the searchbar losing focus.
+- `ionChange` is no longer emitted when the `value` of `ion-searchbar` is modified externally. `ionChange` is only emitted from user committed changes, such as typing in the searchbar and the searchbar losing focus or pressing the "Enter" key.
- If your application requires immediate feedback based on the user typing actively in the searchbar, consider migrating your event listeners to using `ionInput` instead.
@@ -204,6 +204,8 @@ Ionic now listens on the `keydown` event instead of the `keyup` event when deter
- The `debounce` property's default value has changed from 250 to `undefined`. If `debounce` is undefined, the `ionInput` event will fire immediately.
+- The `detail` payload for the `ionInput` event now contains an object with the current `value` as well as the native event that triggered `ionInput`.
+
**Design tokens**
| Token | Previous Value | New Value |
diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts
index 59eed5f824..b21283930a 100644
--- a/angular/src/directives/proxies.ts
+++ b/angular/src/directives/proxies.ts
@@ -1019,7 +1019,7 @@ event is not necessarily fired for each alteration to an element's value.
Depending on the way the users interacts with the element, the `ionChange`
event fires at a different moment:
- When the user commits the change explicitly (e.g. by selecting a date
-from a date picker for ``, etc.).
+from a date picker for ``, pressing the "Enter" key, etc.).
- When the element loses focus after its value has changed: for elements
where the user's interaction is typing.
*/
@@ -1862,21 +1862,23 @@ export class IonSearchbar {
}
+import type { SearchbarInputEventDetail as IIonSearchbarSearchbarInputEventDetail } from '@ionic/core';
import type { SearchbarChangeEventDetail as IIonSearchbarSearchbarChangeEventDetail } from '@ionic/core';
export declare interface IonSearchbar extends Components.IonSearchbar {
/**
* Emitted when the `value` of the `ion-searchbar` element has changed.
*/
- ionInput: EventEmitter>;
+ ionInput: EventEmitter>;
/**
* The `ionChange` event is fired for `` elements when the user
modifies the element's value. Unlike the `ionInput` event, the `ionChange`
event is not necessarily fired for each alteration to an element's value.
-The `ionChange` event is fired when the element loses focus after its value
-has been modified. This includes modifications made when clicking the clear
-or cancel buttons.
+The `ionChange` event is fired when the value has been committed
+by the user. This can happen when the element loses focus or
+when the "Enter" key is pressed. `ionChange` can also fire
+when clicking the clear or cancel buttons.
*/
ionChange: EventEmitter>;
/**
diff --git a/angular/src/index.ts b/angular/src/index.ts
index 7c00685f72..0059a9538b 100644
--- a/angular/src/index.ts
+++ b/angular/src/index.ts
@@ -114,6 +114,7 @@ export {
ScrollCustomEvent,
SearchbarCustomEvent,
SearchbarChangeEventDetail,
+ SearchbarInputEventDetail,
SegmentChangeEventDetail,
SegmentCustomEvent,
SelectChangeEventDetail,
diff --git a/core/api.txt b/core/api.txt
index b25334a075..07d0fbf5e5 100644
--- a/core/api.txt
+++ b/core/api.txt
@@ -1162,7 +1162,7 @@ ion-searchbar,event,ionCancel,void,true
ion-searchbar,event,ionChange,SearchbarChangeEventDetail,true
ion-searchbar,event,ionClear,void,true
ion-searchbar,event,ionFocus,void,true
-ion-searchbar,event,ionInput,KeyboardEvent | null,true
+ion-searchbar,event,ionInput,SearchbarInputEventDetail,true
ion-searchbar,css-prop,--background
ion-searchbar,css-prop,--border-radius
ion-searchbar,css-prop,--box-shadow
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index 3bf00a8428..28f156e818 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -32,7 +32,7 @@ import { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, Rang
import { RefresherEventDetail } from "./components/refresher/refresher-interface";
import { ItemReorderEventDetail } from "./components/reorder-group/reorder-group-interface";
import { NavigationHookCallback } from "./components/route/route-interface";
-import { SearchbarChangeEventDetail } from "./components/searchbar/searchbar-interface";
+import { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./components/searchbar/searchbar-interface";
import { SegmentChangeEventDetail } from "./components/segment/segment-interface";
import { SegmentButtonLayout } from "./components/segment-button/segment-button-interface";
import { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./components/select/select-interface";
@@ -68,7 +68,7 @@ export { PinFormatter, RangeChangeEventDetail, RangeKnobMoveEndEventDetail, Rang
export { RefresherEventDetail } from "./components/refresher/refresher-interface";
export { ItemReorderEventDetail } from "./components/reorder-group/reorder-group-interface";
export { NavigationHookCallback } from "./components/route/route-interface";
-export { SearchbarChangeEventDetail } from "./components/searchbar/searchbar-interface";
+export { SearchbarChangeEventDetail, SearchbarInputEventDetail } from "./components/searchbar/searchbar-interface";
export { SegmentChangeEventDetail } from "./components/segment/segment-interface";
export { SegmentButtonLayout } from "./components/segment-button/segment-button-interface";
export { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./components/select/select-interface";
@@ -5276,7 +5276,7 @@ declare namespace LocalJSX {
*/
"onIonBlur"?: (event: IonInputCustomEvent) => void;
/**
- * The `ionChange` event is fired for `` elements when the user modifies the element's value. Unlike the `ionInput` event, the `ionChange` event is not necessarily fired for each alteration to an element's value. Depending on the way the users interacts with the element, the `ionChange` event fires at a different moment: - When the user commits the change explicitly (e.g. by selecting a date from a date picker for ``, etc.). - When the element loses focus after its value has changed: for elements where the user's interaction is typing.
+ * The `ionChange` event is fired for `` elements when the user modifies the element's value. Unlike the `ionInput` event, the `ionChange` event is not necessarily fired for each alteration to an element's value. Depending on the way the users interacts with the element, the `ionChange` event fires at a different moment: - When the user commits the change explicitly (e.g. by selecting a date from a date picker for ``, pressing the "Enter" key, etc.). - When the element loses focus after its value has changed: for elements where the user's interaction is typing.
*/
"onIonChange"?: (event: IonInputCustomEvent) => void;
/**
@@ -6602,7 +6602,7 @@ declare namespace LocalJSX {
*/
"onIonCancel"?: (event: IonSearchbarCustomEvent) => void;
/**
- * The `ionChange` event is fired for `` elements when the user modifies the element's value. Unlike the `ionInput` event, the `ionChange` event is not necessarily fired for each alteration to an element's value. The `ionChange` event is fired when the element loses focus after its value has been modified. This includes modifications made when clicking the clear or cancel buttons.
+ * The `ionChange` event is fired for `` elements when the user modifies the element's value. Unlike the `ionInput` event, the `ionChange` event is not necessarily fired for each alteration to an element's value. The `ionChange` event is fired when the value has been committed by the user. This can happen when the element loses focus or when the "Enter" key is pressed. `ionChange` can also fire when clicking the clear or cancel buttons.
*/
"onIonChange"?: (event: IonSearchbarCustomEvent) => void;
/**
@@ -6616,7 +6616,7 @@ declare namespace LocalJSX {
/**
* Emitted when the `value` of the `ion-searchbar` element has changed.
*/
- "onIonInput"?: (event: IonSearchbarCustomEvent) => void;
+ "onIonInput"?: (event: IonSearchbarCustomEvent) => void;
/**
* Emitted when the styles change.
*/
diff --git a/core/src/components/input/input.tsx b/core/src/components/input/input.tsx
index aa5ae57252..6d9e8b4177 100644
--- a/core/src/components/input/input.tsx
+++ b/core/src/components/input/input.tsx
@@ -291,10 +291,9 @@ export class Input implements ComponentInterface {
* Depending on the way the users interacts with the element, the `ionChange`
* event fires at a different moment:
* - When the user commits the change explicitly (e.g. by selecting a date
- * from a date picker for ``, etc.).
+ * from a date picker for ``, pressing the "Enter" key, etc.).
* - When the element loses focus after its value has changed: for elements
* where the user's interaction is typing.
- *
*/
@Event() ionChange!: EventEmitter;
diff --git a/core/src/components/searchbar/searchbar-interface.ts b/core/src/components/searchbar/searchbar-interface.ts
index 45697096ae..a4fa573d90 100644
--- a/core/src/components/searchbar/searchbar-interface.ts
+++ b/core/src/components/searchbar/searchbar-interface.ts
@@ -1,5 +1,11 @@
export interface SearchbarChangeEventDetail {
value?: string | null;
+ event?: Event;
+}
+
+export interface SearchbarInputEventDetail {
+ value?: string | null;
+ event?: Event;
}
export interface SearchbarCustomEvent extends CustomEvent {
diff --git a/core/src/components/searchbar/searchbar.tsx b/core/src/components/searchbar/searchbar.tsx
index ab3ee5a508..f4bbcf6b03 100644
--- a/core/src/components/searchbar/searchbar.tsx
+++ b/core/src/components/searchbar/searchbar.tsx
@@ -9,7 +9,7 @@ import { debounceEvent, raf } from '../../utils/helpers';
import { isRTL } from '../../utils/rtl';
import { createColorClasses } from '../../utils/theme';
-import type { SearchbarChangeEventDetail } from './searchbar-interface';
+import type { SearchbarChangeEventDetail, SearchbarInputEventDetail } from './searchbar-interface';
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
@@ -26,7 +26,7 @@ export class Searchbar implements ComponentInterface {
private nativeInput?: HTMLInputElement;
private isCancelVisible = false;
private shouldAlignLeft = true;
- private originalIonInput?: EventEmitter;
+ private originalIonInput?: EventEmitter;
/**
* The value of the input when the textarea is focused.
@@ -165,16 +165,17 @@ export class Searchbar implements ComponentInterface {
/**
* Emitted when the `value` of the `ion-searchbar` element has changed.
*/
- @Event() ionInput!: EventEmitter;
+ @Event() ionInput!: EventEmitter;
/**
* The `ionChange` event is fired for `` elements when the user
* modifies the element's value. Unlike the `ionInput` event, the `ionChange`
* event is not necessarily fired for each alteration to an element's value.
*
- * The `ionChange` event is fired when the element loses focus after its value
- * has been modified. This includes modifications made when clicking the clear
- * or cancel buttons.
+ * The `ionChange` event is fired when the value has been committed
+ * by the user. This can happen when the element loses focus or
+ * when the "Enter" key is pressed. `ionChange` can also fire
+ * when clicking the clear or cancel buttons.
*/
@Event() ionChange!: EventEmitter;
@@ -266,13 +267,21 @@ export class Searchbar implements ComponentInterface {
* This API should be called for user committed changes.
* This API should not be used for external value changes.
*/
- private emitValueChange() {
+ private emitValueChange(event?: Event) {
const { value } = this;
// Checks for both null and undefined values
const newValue = value == null ? value : value.toString();
// Emitting a value change should update the internal state for tracking the focused value
this.focusedValue = newValue;
- this.ionChange.emit({ value: newValue });
+ this.ionChange.emit({ value: newValue, event });
+ }
+
+ /**
+ * Emits an `ionInput` event.
+ */
+ private emitInputChange(event?: Event) {
+ const { value } = this;
+ this.ionInput.emit({ value, event });
}
/**
@@ -288,7 +297,7 @@ export class Searchbar implements ComponentInterface {
const value = this.getValue();
if (value !== '') {
this.value = '';
- this.ionInput.emit(null);
+ this.emitInputChange();
/**
* When tapping clear button
@@ -338,7 +347,7 @@ export class Searchbar implements ComponentInterface {
* manually fire ionChange.
*/
if (value && !focused) {
- this.emitValueChange();
+ this.emitValueChange(ev);
}
if (this.nativeInput) {
@@ -349,29 +358,29 @@ export class Searchbar implements ComponentInterface {
/**
* Update the Searchbar input value when the input changes
*/
- private onInput = (ev: Event) => {
+ private onInput = (ev: InputEvent | Event) => {
const input = ev.target as HTMLInputElement | null;
if (input) {
this.value = input.value;
}
- this.ionInput.emit(ev as KeyboardEvent);
+ this.emitInputChange(ev);
};
- private onChange = () => {
- this.emitValueChange();
+ private onChange = (ev: Event) => {
+ this.emitValueChange(ev);
};
/**
* Sets the Searchbar to not focused and checks if it should align left
* based on whether there is a value in the searchbar or not.
*/
- private onBlur = () => {
+ private onBlur = (ev: FocusEvent) => {
this.focused = false;
this.ionBlur.emit();
this.positionElements();
if (this.focusedValue !== this.value) {
- this.emitValueChange();
+ this.emitValueChange(ev);
}
this.focusedValue = undefined;
};
diff --git a/core/src/components/searchbar/test/events/searchbar.e2e.ts b/core/src/components/searchbar/test/events/searchbar.e2e.ts
index 123443f792..1079957cbc 100644
--- a/core/src/components/searchbar/test/events/searchbar.e2e.ts
+++ b/core/src/components/searchbar/test/events/searchbar.e2e.ts
@@ -15,7 +15,7 @@ test.describe('searchbar: events (ionChange)', () => {
await nativeInput.evaluate((e) => e.blur());
await ionChange.next();
- expect(ionChange).toHaveReceivedEventDetail({ value: 'new value' });
+ expect(ionChange).toHaveReceivedEventDetail({ value: 'new value', event: { isTrusted: true } });
expect(ionChange).toHaveReceivedEventTimes(1);
});
@@ -29,7 +29,7 @@ test.describe('searchbar: events (ionChange)', () => {
await nativeInput.evaluate((e) => e.blur());
await ionChange.next();
- expect(ionChange).toHaveReceivedEventDetail({ value: '' });
+ expect(ionChange).toHaveReceivedEventDetail({ value: '', event: { isTrusted: true } });
expect(ionChange).toHaveReceivedEventTimes(1);
});
@@ -41,7 +41,7 @@ test.describe('searchbar: events (ionChange)', () => {
await page.waitForChanges();
await ionChange.next();
- expect(ionChange).toHaveReceivedEventDetail({ value: '' });
+ expect(ionChange).toHaveReceivedEventDetail({ value: '', event: { isTrusted: true } });
expect(ionChange).toHaveReceivedEventTimes(1);
});
diff --git a/packages/react/src/components/index.ts b/packages/react/src/components/index.ts
index 8508fec79e..32c2cae47e 100644
--- a/packages/react/src/components/index.ts
+++ b/packages/react/src/components/index.ts
@@ -69,6 +69,7 @@ export {
ScrollCustomEvent,
SearchbarCustomEvent,
SearchbarChangeEventDetail,
+ SearchbarInputEventDetail,
SegmentChangeEventDetail,
SegmentCustomEvent,
SelectChangeEventDetail,
diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts
index 91c3d1c94d..69fd44e95b 100644
--- a/packages/vue/src/index.ts
+++ b/packages/vue/src/index.ts
@@ -109,6 +109,7 @@ export {
ScrollCustomEvent,
SearchbarCustomEvent,
SearchbarChangeEventDetail,
+ SearchbarInputEventDetail,
SegmentChangeEventDetail,
SegmentCustomEvent,
SelectChangeEventDetail,