diff --git a/angular/src/directives/proxies.ts b/angular/src/directives/proxies.ts
index c7bc83527c..5636f510b2 100644
--- a/angular/src/directives/proxies.ts
+++ b/angular/src/directives/proxies.ts
@@ -1954,7 +1954,7 @@ export declare interface IonSegmentButton extends Components.IonSegmentButton {}
@ProxyCmp({
- inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'legacy', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'shape', 'value'],
+ inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'expandedIcon', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'legacy', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'shape', 'toggleIcon', 'value'],
methods: ['open']
})
@Component({
@@ -1962,7 +1962,7 @@ export declare interface IonSegmentButton extends Components.IonSegmentButton {}
changeDetection: ChangeDetectionStrategy.OnPush,
template: '',
// eslint-disable-next-line @angular-eslint/no-inputs-metadata-property
- inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'legacy', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'shape', 'value'],
+ inputs: ['cancelText', 'color', 'compareWith', 'disabled', 'expandedIcon', 'fill', 'interface', 'interfaceOptions', 'justify', 'label', 'labelPlacement', 'legacy', 'mode', 'multiple', 'name', 'okText', 'placeholder', 'selectedText', 'shape', 'toggleIcon', 'value'],
})
export class IonSelect {
protected el: HTMLElement;
diff --git a/core/api.txt b/core/api.txt
index 04df06ad12..eecee0c71f 100644
--- a/core/api.txt
+++ b/core/api.txt
@@ -1238,6 +1238,7 @@ ion-select,prop,cancelText,string,'Cancel',false,false
ion-select,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record | undefined,undefined,false,true
ion-select,prop,compareWith,((currentValue: any, compareValue: any) => boolean) | null | string | undefined,undefined,false,false
ion-select,prop,disabled,boolean,false,false,false
+ion-select,prop,expandedIcon,string | undefined,undefined,false,false
ion-select,prop,fill,"outline" | "solid" | undefined,undefined,false,false
ion-select,prop,interface,"action-sheet" | "alert" | "popover",'alert',false,false
ion-select,prop,interfaceOptions,any,{},false,false
@@ -1252,6 +1253,7 @@ ion-select,prop,okText,string,'OK',false,false
ion-select,prop,placeholder,string | undefined,undefined,false,false
ion-select,prop,selectedText,null | string | undefined,undefined,false,false
ion-select,prop,shape,"round" | undefined,undefined,false,false
+ion-select,prop,toggleIcon,string | undefined,undefined,false,false
ion-select,prop,value,any,undefined,false,false
ion-select,method,open,open(event?: UIEvent) => Promise
ion-select,event,ionBlur,void,true
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index b65f10b179..a85b7cfcfb 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -2681,6 +2681,10 @@ export namespace Components {
* If `true`, the user cannot interact with the select.
*/
"disabled": boolean;
+ /**
+ * The toggle icon to show when the select is open. If defined, the icon rotation behavior in `md` mode will be disabled. If undefined, `toggleIcon` will be used for when the select is both open and closed.
+ */
+ "expandedIcon"?: string;
/**
* The fill for the item. If `"solid"` the item will have a background. If `"outline"` the item will be transparent with a border. Only available in `md` mode.
*/
@@ -2742,6 +2746,10 @@ export namespace Components {
* The shape of the select. If "round" it will have an increased border radius.
*/
"shape"?: 'round';
+ /**
+ * The toggle icon to use. Defaults to `chevronExpand` for `ios` mode, or `caretDownSharp` for `md` mode.
+ */
+ "toggleIcon"?: string;
/**
* The value of the select.
*/
@@ -6755,6 +6763,10 @@ declare namespace LocalJSX {
* If `true`, the user cannot interact with the select.
*/
"disabled"?: boolean;
+ /**
+ * The toggle icon to show when the select is open. If defined, the icon rotation behavior in `md` mode will be disabled. If undefined, `toggleIcon` will be used for when the select is both open and closed.
+ */
+ "expandedIcon"?: string;
/**
* The fill for the item. If `"solid"` the item will have a background. If `"outline"` the item will be transparent with a border. Only available in `md` mode.
*/
@@ -6835,6 +6847,10 @@ declare namespace LocalJSX {
* The shape of the select. If "round" it will have an increased border radius.
*/
"shape"?: 'round';
+ /**
+ * The toggle icon to use. Defaults to `chevronExpand` for `ios` mode, or `caretDownSharp` for `md` mode.
+ */
+ "toggleIcon"?: string;
/**
* The value of the select.
*/
diff --git a/core/src/components/select/select.md.scss b/core/src/components/select/select.md.scss
index ffbd004520..fa7c621c40 100644
--- a/core/src/components/select/select.md.scss
+++ b/core/src/components/select/select.md.scss
@@ -94,7 +94,7 @@
* when the select is activated.
* This should only happen on MD.
*/
-:host(.select-expanded:not(.legacy-select)) .select-icon {
+:host(.select-expanded:not(.legacy-select):not(.has-expanded-icon)) .select-icon {
@include transform(rotate(180deg));
}
@@ -123,7 +123,7 @@
@include transform(translate3d(0, -9px, 0));
}
-:host-context(.item-has-focus) .select-icon {
+:host-context(.item-has-focus):host(:not(.has-expanded-icon)) .select-icon {
@include transform(rotate(180deg));
}
@@ -131,8 +131,8 @@
* Ensure that the translation we did
* above is preserved when we rotate the select icon.
*/
-:host-context(.item-has-focus.item-label-stacked) .select-icon,
-:host-context(.item-has-focus.item-label-floating:not(.item-fill-outline)) .select-icon {
+:host-context(.item-has-focus.item-label-stacked):host(:not(.has-expanded-icon)) .select-icon,
+:host-context(.item-has-focus.item-label-floating:not(.item-fill-outline)):host(:not(.has-expanded-icon)) .select-icon {
@include transform(rotate(180deg), translate3d(0, -9px, 0));
}
diff --git a/core/src/components/select/select.tsx b/core/src/components/select/select.tsx
index 49999a24f2..639d8e22a3 100644
--- a/core/src/components/select/select.tsx
+++ b/core/src/components/select/select.tsx
@@ -183,6 +183,19 @@ export class Select implements ComponentInterface {
*/
@Prop() selectedText?: string | null;
+ /**
+ * The toggle icon to use. Defaults to `chevronExpand` for `ios` mode,
+ * or `caretDownSharp` for `md` mode.
+ */
+ @Prop() toggleIcon?: string;
+
+ /**
+ * The toggle icon to show when the select is open. If defined, the icon
+ * rotation behavior in `md` mode will be disabled. If undefined, `toggleIcon`
+ * will be used for when the select is both open and closed.
+ */
+ @Prop() expandedIcon?: string;
+
/**
* The shape of the select. If "round" it will have an increased border radius.
*/
@@ -820,7 +833,8 @@ export class Select implements ComponentInterface {
}
private renderSelect() {
- const { disabled, el, isExpanded, labelPlacement, justify, placeholder, fill, shape, name, value } = this;
+ const { disabled, el, isExpanded, expandedIcon, labelPlacement, justify, placeholder, fill, shape, name, value } =
+ this;
const mode = getIonMode(this);
const hasFloatingOrStackedLabel = labelPlacement === 'floating' || labelPlacement === 'stacked';
const justifyEnabled = !hasFloatingOrStackedLabel;
@@ -839,6 +853,7 @@ export class Select implements ComponentInterface {
'in-item-color': hostContext('ion-item.ion-color', el),
'select-disabled': disabled,
'select-expanded': isExpanded,
+ 'has-expanded-icon': expandedIcon !== undefined,
'has-value': this.hasValue(),
'has-placeholder': placeholder !== undefined,
'ion-focusable': true,
@@ -893,7 +908,7 @@ Developers can use the "legacy" property to continue using the legacy form marku
this.hasLoggedDeprecationWarning = true;
}
- const { disabled, el, inputId, isExpanded, name, placeholder, value } = this;
+ const { disabled, el, inputId, isExpanded, expandedIcon, name, placeholder, value } = this;
const mode = getIonMode(this);
const { labelText, labelId } = getAriaLabel(el, inputId);
@@ -926,6 +941,7 @@ Developers can use the "legacy" property to continue using the legacy form marku
'in-item-color': hostContext('ion-item.ion-color', el),
'select-disabled': disabled,
'select-expanded': isExpanded,
+ 'has-expanded-icon': expandedIcon !== undefined,
'legacy-select': true,
}}
>
@@ -974,7 +990,16 @@ Developers can use the "legacy" property to continue using the legacy form marku
*/
private renderSelectIcon() {
const mode = getIonMode(this);
- const icon = mode === 'ios' ? chevronExpand : caretDownSharp;
+ const { isExpanded, toggleIcon, expandedIcon } = this;
+ let icon: string;
+
+ if (isExpanded && expandedIcon !== undefined) {
+ icon = expandedIcon;
+ } else {
+ const defaultIcon = mode === 'ios' ? chevronExpand : caretDownSharp;
+ icon = toggleIcon ?? defaultIcon;
+ }
+
return ;
}
diff --git a/core/src/components/select/test/toggle-icon/index.html b/core/src/components/select/test/toggle-icon/index.html
new file mode 100644
index 0000000000..1c144416bb
--- /dev/null
+++ b/core/src/components/select/test/toggle-icon/index.html
@@ -0,0 +1,58 @@
+
+
+
+
+ Select - toggleIcon
+
+
+
+
+
+
+
+
+
+
+
+
+ Select - toggleIcon
+
+
+
+
+
+
+
+ Apples
+ Oranges
+ Pears
+
+
+
+
+ Apples
+ Oranges
+ Pears
+
+
+
+
+ Apples
+ Oranges
+ Pears
+
+
+
+
+
+
+
diff --git a/core/src/components/select/test/toggle-icon/select.e2e.ts b/core/src/components/select/test/toggle-icon/select.e2e.ts
new file mode 100644
index 0000000000..c956429358
--- /dev/null
+++ b/core/src/components/select/test/toggle-icon/select.e2e.ts
@@ -0,0 +1,39 @@
+import { expect } from '@playwright/test';
+import { configs, test } from '@utils/test/playwright';
+
+configs({ directions: ['ltr'], modes: ['md'] }).forEach(({ title, screenshot, config }) => {
+ test.describe(title('select: toggleIcon'), () => {
+ test('should render a custom toggleIcon', async ({ page }) => {
+ await page.setContent(
+ `
+
+ Apple
+
+ `,
+ config
+ );
+
+ const select = page.locator('ion-select');
+ await expect(select).toHaveScreenshot(screenshot(`select-toggle-icon`));
+ });
+
+ test('should render a custom expandedIcon', async ({ page }) => {
+ await page.setContent(
+ `
+
+ Apple
+
+ `,
+ config
+ );
+
+ const select = page.locator('ion-select');
+ const popoverDidPresent = await page.spyOnEvent('ionPopoverDidPresent');
+
+ await select.click();
+ await popoverDidPresent.next();
+
+ await expect(select).toHaveScreenshot(screenshot(`select-expanded-icon`));
+ });
+ });
+});
diff --git a/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Chrome-linux.png b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Chrome-linux.png
new file mode 100644
index 0000000000..beb10c2593
Binary files /dev/null and b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Firefox-linux.png b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Firefox-linux.png
new file mode 100644
index 0000000000..fb9550dbb3
Binary files /dev/null and b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Safari-linux.png b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Safari-linux.png
new file mode 100644
index 0000000000..e3592b3ddf
Binary files /dev/null and b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-expanded-icon-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Chrome-linux.png b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Chrome-linux.png
new file mode 100644
index 0000000000..78512cad71
Binary files /dev/null and b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Firefox-linux.png b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Firefox-linux.png
new file mode 100644
index 0000000000..95155e5a6d
Binary files /dev/null and b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Safari-linux.png b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Safari-linux.png
new file mode 100644
index 0000000000..f80cd24d98
Binary files /dev/null and b/core/src/components/select/test/toggle-icon/select.e2e.ts-snapshots/select-toggle-icon-md-ltr-Mobile-Safari-linux.png differ
diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts
index 88a6bc0010..23131fb7bc 100644
--- a/packages/vue/src/proxies.ts
+++ b/packages/vue/src/proxies.ts
@@ -739,6 +739,8 @@ export const IonSelect = /*@__PURE__*/ defineContainer