diff --git a/core/api.txt b/core/api.txt
index e4e1ca4d603..4bf94c415f6 100644
--- a/core/api.txt
+++ b/core/api.txt
@@ -2326,6 +2326,24 @@ ion-select,css-prop,--placeholder-opacity,md
ion-select,css-prop,--ripple-color,ionic
ion-select,css-prop,--ripple-color,ios
ion-select,css-prop,--ripple-color,md
+ion-select,css-prop,--select-text-media-border-color,ionic
+ion-select,css-prop,--select-text-media-border-color,ios
+ion-select,css-prop,--select-text-media-border-color,md
+ion-select,css-prop,--select-text-media-border-radius,ionic
+ion-select,css-prop,--select-text-media-border-radius,ios
+ion-select,css-prop,--select-text-media-border-radius,md
+ion-select,css-prop,--select-text-media-border-style,ionic
+ion-select,css-prop,--select-text-media-border-style,ios
+ion-select,css-prop,--select-text-media-border-style,md
+ion-select,css-prop,--select-text-media-border-width,ionic
+ion-select,css-prop,--select-text-media-border-width,ios
+ion-select,css-prop,--select-text-media-border-width,md
+ion-select,css-prop,--select-text-media-height,ionic
+ion-select,css-prop,--select-text-media-height,ios
+ion-select,css-prop,--select-text-media-height,md
+ion-select,css-prop,--select-text-media-width,ionic
+ion-select,css-prop,--select-text-media-width,ios
+ion-select,css-prop,--select-text-media-width,md
ion-select,part,bottom
ion-select,part,container
ion-select,part,error-text
@@ -2345,6 +2363,7 @@ ion-select-modal,prop,multiple,boolean | undefined,undefined,false,false
ion-select-modal,prop,options,SelectModalOption[],[],false,false
ion-select-option,shadow
+ion-select-option,prop,description,string | undefined,undefined,false,false
ion-select-option,prop,disabled,boolean,false,false,false
ion-select-option,prop,mode,"ios" | "md",undefined,false,false
ion-select-option,prop,theme,"ios" | "md" | "ionic",undefined,false,false
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index ecbdb7475c6..86ac882a669 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -3813,6 +3813,10 @@ export namespace Components {
"options": SelectModalOption[];
}
interface IonSelectOption {
+ /**
+ * Text that is placed underneath the option text to provide additional details about the option.
+ */
+ "description"?: string;
/**
* If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons.
* @default false
@@ -9897,6 +9901,10 @@ declare namespace LocalJSX {
"options"?: SelectModalOption[];
}
interface IonSelectOption {
+ /**
+ * Text that is placed underneath the option text to provide additional details about the option.
+ */
+ "description"?: string;
/**
* If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons.
* @default false
@@ -11268,6 +11276,7 @@ declare namespace LocalJSX {
interface IonSelectOptionAttributes {
"disabled": boolean;
"value": string;
+ "description": string;
}
interface IonSelectPopoverAttributes {
"header": string;
diff --git a/core/src/components/action-sheet/action-sheet.scss b/core/src/components/action-sheet/action-sheet.common.scss
similarity index 96%
rename from core/src/components/action-sheet/action-sheet.scss
rename to core/src/components/action-sheet/action-sheet.common.scss
index 2a2f85bb456..7e857346ac9 100644
--- a/core/src/components/action-sheet/action-sheet.scss
+++ b/core/src/components/action-sheet/action-sheet.common.scss
@@ -233,3 +233,20 @@
}
}
}
+
+// Action Sheet: Select Option
+// --------------------------------------------------
+
+.action-sheet-button-label {
+ display: flex;
+
+ align-items: center;
+}
+
+.select-option-content {
+ flex: 1;
+}
+
+.select-option-description {
+ display: block;
+}
diff --git a/core/src/components/action-sheet/action-sheet.ionic.scss b/core/src/components/action-sheet/action-sheet.ionic.scss
new file mode 100644
index 00000000000..b2c749d4e0a
--- /dev/null
+++ b/core/src/components/action-sheet/action-sheet.ionic.scss
@@ -0,0 +1,22 @@
+@use "../../themes/ionic/ionic.globals.scss" as globals;
+@use "./action-sheet.common";
+@use "./action-sheet.md" as action-sheet-md;
+
+// Ionic Action Sheet
+// --------------------------------------------------
+
+// Action Sheet: Select Option
+// --------------------------------------------------
+
+.action-sheet-button-label {
+ gap: globals.$ion-space-300;
+}
+
+.select-option-description {
+ @include globals.typography(globals.$ion-body-md-regular);
+ @include globals.padding(0);
+
+ color: globals.$ion-text-subtle;
+
+ font-size: globals.$ion-font-size-350;
+}
diff --git a/core/src/components/action-sheet/action-sheet.ios.scss b/core/src/components/action-sheet/action-sheet.ios.scss
index fe9bba89903..94b98447981 100644
--- a/core/src/components/action-sheet/action-sheet.ios.scss
+++ b/core/src/components/action-sheet/action-sheet.ios.scss
@@ -1,4 +1,4 @@
-@import "./action-sheet";
+@import "./action-sheet.native";
@import "./action-sheet.ios.vars";
// iOS Action Sheet
diff --git a/core/src/components/action-sheet/action-sheet.md.scss b/core/src/components/action-sheet/action-sheet.md.scss
index 8e1c7f07027..e46f06085b3 100644
--- a/core/src/components/action-sheet/action-sheet.md.scss
+++ b/core/src/components/action-sheet/action-sheet.md.scss
@@ -1,4 +1,4 @@
-@import "./action-sheet";
+@import "./action-sheet.native";
@import "./action-sheet.md.vars";
// Material Design Action Sheet Title
diff --git a/core/src/components/action-sheet/action-sheet.native.scss b/core/src/components/action-sheet/action-sheet.native.scss
new file mode 100644
index 00000000000..affa6aeb126
--- /dev/null
+++ b/core/src/components/action-sheet/action-sheet.native.scss
@@ -0,0 +1,19 @@
+@use "../../themes/native/native.theme.default" as native;
+@use "../../themes/mixins" as mixins;
+@use "../../themes/functions.font" as font;
+@use "./action-sheet.common";
+
+// Action Sheet: Native
+// --------------------------------------------------
+
+.action-sheet-button-label {
+ gap: 12px;
+}
+
+.select-option-description {
+ @include mixins.padding(5px, 0, 0, 0);
+
+ color: native.$text-color-step-300;
+
+ font-size: font.dynamic-font(12px);
+}
diff --git a/core/src/components/action-sheet/action-sheet.tsx b/core/src/components/action-sheet/action-sheet.tsx
index 5d79ab90f51..9c5a112ab62 100644
--- a/core/src/components/action-sheet/action-sheet.tsx
+++ b/core/src/components/action-sheet/action-sheet.tsx
@@ -16,11 +16,13 @@ import {
safeCall,
setOverlayId,
} from '@utils/overlays';
+import { renderOptionLabel } from '@utils/select-option-render';
import { getClassMap } from '@utils/theme';
import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, CssClassMap, FrameworkDelegate, OverlayInterface } from '../../interface';
import type { OverlayEventDetail } from '../../utils/overlays-interface';
+import type { SelectActionSheetButton } from '../select/select-interface';
import type { ActionSheetButton } from './action-sheet-interface';
import { iosEnterAnimation } from './animations/ios.enter';
@@ -37,7 +39,7 @@ import { mdLeaveAnimation } from './animations/md.leave';
styleUrls: {
ios: 'action-sheet.ios.scss',
md: 'action-sheet.md.scss',
- ionic: 'action-sheet.md.scss',
+ ionic: 'action-sheet.ionic.scss',
},
scoped: true,
})
@@ -559,6 +561,21 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
htmlAttrs['aria-checked'] = isActiveRadio ? 'true' : 'false';
}
+ /**
+ * Cast to `SelectActionSheetButton` to access rich content
+ * fields (`startContent`, `endContent`, `description`)
+ * that are passed through from `ion-select` but not
+ * part of the public `ActionSheetButton` interface.
+ */
+ const richButton = b as SelectActionSheetButton;
+ const optionLabelOptions = {
+ id: buttonId,
+ label: richButton.text,
+ startContent: richButton.startContent,
+ endContent: richButton.endContent,
+ description: richButton.description,
+ };
+
return (
diff --git a/core/src/components/alert/alert.scss b/core/src/components/alert/alert.common.scss
similarity index 95%
rename from core/src/components/alert/alert.scss
rename to core/src/components/alert/alert.common.scss
index 9948a4127a9..84e35eca5c3 100644
--- a/core/src/components/alert/alert.scss
+++ b/core/src/components/alert/alert.common.scss
@@ -247,3 +247,21 @@ textarea.alert-input {
min-height: $alert-input-min-height;
resize: none;
}
+
+// Alert Button: Select Option
+// --------------------------------------------------
+
+.alert-radio-label,
+.alert-checkbox-label {
+ display: flex;
+
+ align-items: center;
+}
+
+.select-option-content {
+ flex: 1;
+}
+
+.select-option-description {
+ display: block;
+}
diff --git a/core/src/components/alert/alert.ionic.scss b/core/src/components/alert/alert.ionic.scss
new file mode 100644
index 00000000000..3c54136b477
--- /dev/null
+++ b/core/src/components/alert/alert.ionic.scss
@@ -0,0 +1,23 @@
+@use "../../themes/ionic/ionic.globals.scss" as globals;
+@use "./alert.common";
+@use "./alert.md" as alert-md;
+
+// Ionic Alert
+// --------------------------------------------------
+
+// Alert: Select Option
+// --------------------------------------------------
+
+.alert-radio-label,
+.alert-checkbox-label {
+ gap: globals.$ion-space-300;
+}
+
+.select-option-description {
+ @include globals.typography(globals.$ion-body-md-regular);
+ @include globals.padding(0);
+
+ color: globals.$ion-text-subtle;
+
+ font-size: globals.$ion-font-size-350;
+}
diff --git a/core/src/components/alert/alert.ios.scss b/core/src/components/alert/alert.ios.scss
index 714efc03baf..2671dc0940b 100644
--- a/core/src/components/alert/alert.ios.scss
+++ b/core/src/components/alert/alert.ios.scss
@@ -1,4 +1,4 @@
-@import "./alert";
+@import "./alert.native";
@import "./alert.ios.vars";
// iOS Alert
diff --git a/core/src/components/alert/alert.md.scss b/core/src/components/alert/alert.md.scss
index 5ac468c760f..2fbd0fd8775 100644
--- a/core/src/components/alert/alert.md.scss
+++ b/core/src/components/alert/alert.md.scss
@@ -1,4 +1,4 @@
-@import "./alert";
+@import "./alert.native";
@import "./alert.md.vars";
// Material Design Alert
diff --git a/core/src/components/alert/alert.native.scss b/core/src/components/alert/alert.native.scss
new file mode 100644
index 00000000000..e2d5a87b8a5
--- /dev/null
+++ b/core/src/components/alert/alert.native.scss
@@ -0,0 +1,20 @@
+@use "../../themes/native/native.theme.default" as native;
+@use "../../themes/mixins" as mixins;
+@use "../../themes/functions.font" as font;
+@use "./alert.common";
+
+// Alert: Native
+// --------------------------------------------------
+
+.alert-radio-label,
+.alert-checkbox-label {
+ gap: 12px;
+}
+
+.select-option-description {
+ @include mixins.padding(5px, 0, 0, 0);
+
+ color: native.$text-color-step-300;
+
+ font-size: font.dynamic-font(12px);
+}
diff --git a/core/src/components/alert/alert.tsx b/core/src/components/alert/alert.tsx
index e4e98b67a42..db9ed59c9ce 100644
--- a/core/src/components/alert/alert.tsx
+++ b/core/src/components/alert/alert.tsx
@@ -19,6 +19,7 @@ import {
setOverlayId,
} from '@utils/overlays';
import { sanitizeDOMString } from '@utils/sanitization';
+import { renderOptionLabel } from '@utils/select-option-render';
import { getClassMap } from '@utils/theme';
import { config } from '../../global/config';
@@ -26,6 +27,7 @@ import { getIonMode, getIonTheme } from '../../global/ionic-global';
import type { AnimationBuilder, CssClassMap, OverlayInterface, FrameworkDelegate } from '../../interface';
import type { OverlayEventDetail } from '../../utils/overlays-interface';
import type { IonicSafeString } from '../../utils/sanitization';
+import type { SelectAlertInput } from '../select/select-interface';
import type { AlertButton, AlertInput } from './alert-interface';
import { iosEnterAnimation } from './animations/ios.enter';
@@ -44,7 +46,7 @@ import { mdLeaveAnimation } from './animations/md.leave';
styleUrls: {
ios: 'alert.ios.scss',
md: 'alert.md.scss',
- ionic: 'alert.md.scss',
+ ionic: 'alert.ionic.scss',
},
scoped: true,
})
@@ -329,25 +331,20 @@ export class Alert implements ComponentInterface, OverlayInterface {
}
this.inputType = inputTypes.values().next().value;
- this.processedInputs = inputs.map(
- (i, index) =>
- ({
- type: i.type || 'text',
- name: i.name || `${index}`,
- placeholder: i.placeholder || '',
- value: i.value,
- label: i.label,
- checked: !!i.checked,
- disabled: !!i.disabled,
- id: i.id || `alert-input-${this.overlayIndex}-${index}`,
- handler: i.handler,
- min: i.min,
- max: i.max,
- cssClass: i.cssClass ?? '',
- attributes: i.attributes || {},
- tabindex: i.type === 'radio' && i !== focusable ? -1 : 0,
- } as AlertInput)
- );
+ this.processedInputs = inputs.map((i, index) => {
+ return {
+ ...i,
+ type: i.type || 'text',
+ name: i.name || `${index}`,
+ placeholder: i.placeholder || '',
+ checked: !!i.checked,
+ disabled: !!i.disabled,
+ id: i.id || `alert-input-${this.overlayIndex}-${index}`,
+ cssClass: i.cssClass ?? '',
+ attributes: i.attributes || {},
+ tabindex: i.type === 'radio' && i !== focusable ? -1 : 0,
+ } as AlertInput;
+ });
}
connectedCallback() {
@@ -569,33 +566,50 @@ export class Alert implements ComponentInterface, OverlayInterface {
return (
- {inputs.map((i) => (
-