- The deprecated color step CSS variables, `--ion-color-step-[number]`, have been removed and should be replaced with either `--ion-background-color-step-[number]` or `--ion-text-color-step-[number]` depending on the specific use case, as outlined in the [migration guide](https://ionicframework.com/docs/updating/8-0#step-color-tokens).
-
Components
+
Components
-
Button
+
Button
- The `border-radius` of the `ios` and `md` button now defaults to `6px` and `999px` instead of `14px` and `4px`, respectively, in accordance with the iOS and Material Design 3 guidelines. To revert to the previous appearance, set the `shape` to `"soft"` for `md` and override the `--border-radius` CSS variable for `ios` to `14px`, or set it to a different value entirely.
-
Card
+
Card
- **ion-card**: The `border-radius` of the `ios` and `md` card now defaults to `14px` and `12px` instead of `8px` and `4px`, respectively, in accordance with the iOS and Material Design 3 guidelines. To revert to the previous appearance, set the `shape` to `"soft"`, or override the `--border-radius` CSS variable to specify a different value.
@@ -80,7 +84,30 @@ This is a comprehensive list of the breaking changes introduced in the major ver
}
```
-
Chip
+
Checkbox
+
+- The `container` CSS shadow part is now the element that wraps the checkmark instead of the `svg` element that draws it. The part still controls the checkbox's size, border, and background, so existing styles for those properties are unaffected.
+
+ SVG-specific properties such as `fill`, `stroke` and `stroke-width` no longer have any effect through `::part(container)` because `container` is no longer an SVG element. To set the color of the checkmark, use the `icon` part instead:
+
+ ```diff
+ - ion-checkbox::part(container) {
+ - stroke: purple;
+ - }
+ + ion-checkbox::part(icon) {
+ + color: purple;
+ + }
+ ```
+
+ The `--checkmark-color` CSS variable can also be used to set the checkmark color. Both `::part(icon)` and `--checkmark-color` apply to the default checkmark as well as to an icon set with the `checkboxCheckedIcon` or `checkboxIndeterminateIcon` global config options. In contrast, the `mark` part only applies to states that do not have a configured icon.
+
+ Setting `color` on the `container` part has no effect because the icon sets its own color.
+
+ To change the thickness of the default checkmark, use the `--checkmark-width` CSS variable or set `stroke-width` on the `mark` part. These apply to each state (`checked` and `indeterminate`) unless an icon is configured for that state. For example, when `checkboxCheckedIcon` is configured, these properties do not apply to the checked state but continue to apply to the indeterminate state. Similarly, when `checkboxIndeterminateIcon` is configured, they do not apply to the indeterminate state but continue to apply to the checked state.
+
+ For a configured Ionicon drawn with a stroke, set `--ionicon-stroke-width` on the `icon` part. For a configured SVG, set `stroke-width` on the `icon` part; this applies unless the SVG sets its own `stroke-width`.
+
+
Chip
- Component CSS variables have been removed. The component now utilizes the centralized Ionic Theming system. Global updates should be managed via the theme tokens file, while component-specific overrides are handled through localized CSS variables.
- `--color` is replaced by `IonChip.hue.bold.solid.default` for global styles and `--ion-chip-hue-bold-solid-default-color` for component-specific styles if the chip has a bold hue and solid fill.
@@ -91,26 +118,26 @@ This is a comprehensive list of the breaking changes introduced in the major ver
- Specific theme classes (e.g., `ion-chip.md`) are no longer supported. Style modifications based on the active theme must be implemented using theme tokens rather than direct class targeting.
- The `border-radius` of the `ios` and `md` chip now defaults to `10px` and `8px`, respectively, instead of `16px` in accordance with the iOS and Material Design 3 guidelines. To revert to the previous appearance, set the `shape` to `"round"`, or override the `IonChip.shape.round.border.radius` to specify a different value for global styles and `--ion-chip-shape-round-border-radius` for component-specific styles.
-
Col
+
Col
The following breaking changes apply to `ion-col`:
-1. `--ion-grid-column-padding-*` CSS variables have been replaced with per-side, per-breakpoint tokens in the `col` namespace. [1](#version-9x-col-padding-variables)
-2. Theme classes (`ion-col.md`, `ion-col.ios`) are no longer supported. [2](#version-9x-col-theme-classes)
+1. `--ion-grid-column-padding-*` CSS variables have been replaced with per-side, per-breakpoint tokens in the `col` namespace. [1](#version-10x-col-padding-variables)
+2. Theme classes (`ion-col.md`, `ion-col.ios`) are no longer supported. [2](#version-10x-col-theme-classes)
-
Padding variables
+
Padding variables
Column padding was a single value per breakpoint and is now set per-side, and the variables have moved from the `grid` namespace to the `col` namespace. Use the new token structure for global styles, or the corresponding CSS variable for component-specific overrides:
-| Old (8.x) | New token (global) | New CSS variable (component-specific) |
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--ion-grid-column-padding-{bp}` | `IonCol.breakpoint.{bp}.padding.{top\|end\|bottom\|start}` | `--ion-col-breakpoint-{bp}-padding-{top\|end\|bottom\|start}` |
-
Theme classes
+
Theme classes
Remove any instances that target the theme classes: `ion-col.md`, `ion-col.ios`.
-
Content
+
Content
The following breaking changes apply to `ion-content`:
@@ -123,7 +150,7 @@ The following breaking changes apply to `ion-content`:
`--background` and `--color` have been removed. Use the new token structure for global styles, or the corresponding CSS variable for component-specific overrides:
-| Old (8.x) | New token (global) | New CSS variable (component-specific) |
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--background` | `IonContent.background` | `--ion-content-default-background` |
| `--color` | `IonContent.color` | `--ion-content-default-color` |
@@ -132,7 +159,7 @@ The following breaking changes apply to `ion-content`:
New code should use the token-based API:
-| Old (8.x) | New token (global) | New CSS variable (component-specific) |
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--padding-top` | `IonContent.padding.top` | `--ion-content-padding-top` |
| `--padding-end` | `IonContent.padding.end` | `--ion-content-padding-end` |
@@ -146,7 +173,7 @@ New code should use the token-based API:
The following CSS variables were previously documented `@prop`s on `ion-content` and have been renamed to the `--internal-*` namespace, removing them from the public API:
-| Old (8.x) | New |
+| Old (9.x) | New |
|---|---|
| `--keyboard-offset` | `--internal-keyboard-offset` |
| `--offset-top` | `--internal-offset-top` |
@@ -158,40 +185,40 @@ These are managed by `ion-content` itself (keyboard avoidance and header/footer
Remove any instances that target the theme classes: `ion-content.md`, `ion-content.ios`.
-
Datetime
+
Datetime
- The `ion-buttons` component has been removed from the internal implementation of `ion-datetime` and is no longer required when passing custom buttons to the `slot="buttons"`. When providing custom buttons, use a `div` element instead of `ion-buttons`. While existing code using `ion-buttons` may continue to work visually, future updates to the `ion-buttons` component may cause any styles you rely on to break.
-
Grid
+
Grid
The following breaking changes apply to `ion-grid`:
-1. `--ion-grid-padding-*` CSS variables have been replaced with per-side, per-breakpoint tokens. [1](#version-9x-grid-padding-variables)
-2. `--ion-grid-width-*` CSS variables for the fixed grid have been replaced with per-breakpoint tokens. [2](#version-9x-grid-fixed-width-variables)
-3. The `push` and `pull` properties have been deprecated. [3](#version-9x-grid-deprecated-push-and-pull-properties)
-4. Theme classes (`ion-grid.md`, `ion-grid.ios`) are no longer supported. [4](#version-9x-grid-theme-classes)
+1. `--ion-grid-padding-*` CSS variables have been replaced with per-side, per-breakpoint tokens. [1](#version-10x-grid-padding-variables)
+2. `--ion-grid-width-*` CSS variables for the fixed grid have been replaced with per-breakpoint tokens. [2](#version-10x-grid-fixed-width-variables)
+3. The `push` and `pull` properties have been deprecated. [3](#version-10x-grid-deprecated-push-and-pull-properties)
+4. Theme classes (`ion-grid.md`, `ion-grid.ios`) are no longer supported. [4](#version-10x-grid-theme-classes)
-
Padding variables
+
Padding variables
Grid padding was a single value per breakpoint and is now set per-side. Use the new token structure for global styles, or the corresponding CSS variable for component-specific overrides:
-| Old (8.x) | New token (global) | New CSS variable (component-specific) |
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--ion-grid-padding-{bp}` | `IonGrid.breakpoint.{bp}.padding.{top\|end\|bottom\|start}` | `--ion-grid-breakpoint-{bp}-padding-{top\|end\|bottom\|start}` |
-
Fixed width variables
+
Fixed width variables
-| Old (8.x) | New token (global) | New CSS variable (component-specific) |
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--ion-grid-width-{bp}` | `IonGrid.breakpoint.{bp}.width` | `--ion-grid-breakpoint-{bp}-width` |
-
Deprecated push and pull properties
+
Deprecated push and pull properties
The `push` and `pull` properties have been disabled. They now log a deprecation warning and no longer affect layout. Use the `order` property to achieve a similar result.
**Example 1: Swap two columns**
-**Version up to 8.x**
+**Version up to 9.x**
```html
@@ -203,7 +230,7 @@ The `push` and `pull` properties have been disabled. They now log a deprecation
```
-**Version 9.x+**
+**Version 10.x+**
```html
@@ -219,7 +246,7 @@ The `push` and `pull` properties have been disabled. They now log a deprecation
To reorder two columns where column 1 has `size="9" push="3"` and column 2 has `size="3" pull="9"`:
-**Version up to 8.x**
+**Version up to 9.x**
```html
@@ -230,7 +257,7 @@ To reorder two columns where column 1 has `size="9" push="3"` and column 2 has `
```
-**Version 9.x+**
+**Version 10.x+**
```html
@@ -243,6 +270,8 @@ To reorder two columns where column 1 has `size="9" push="3"` and column 2 has `
**Example 3: Push**
+**Version up to 9.x**
+
```html
@@ -256,7 +285,7 @@ To reorder two columns where column 1 has `size="9" push="3"` and column 2 has `
```
-**Version 9.x+**
+**Version 10.x+**
```html
@@ -273,6 +302,8 @@ To reorder two columns where column 1 has `size="9" push="3"` and column 2 has `
**Example 4: Push and Pull**
+**Version up to 9.x**
+
```html
@@ -286,7 +317,7 @@ To reorder two columns where column 1 has `size="9" push="3"` and column 2 has `
```
-**Version 9.x+**
+**Version 10.x+**
```html
@@ -301,11 +332,11 @@ To reorder two columns where column 1 has `size="9" push="3"` and column 2 has `
```
-
Theme classes
+
Theme classes
Remove any instances that target the theme classes: `ion-grid.md`, `ion-grid.ios`.
-
Image
+
Image
The following breaking changes apply to `ion-img`:
@@ -315,13 +346,13 @@ The following breaking changes apply to `ion-img`:
Remove any instances that target the theme classes: `ion-img.md`, `ion-img.ios`.
-
Input Otp
+
Input Otp
Converted `ion-input-otp` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).
If you were targeting the internals of `ion-input-otp` in your CSS, you will need to target the `group`, `container`, `native`, `separator` or `description` [Shadow Parts](https://ionicframework.com/docs/theming/css-shadow-parts) instead, or use the provided CSS Variables.
-
Item Divider
+
Item Divider
- Component CSS variables have been removed. The component now utilizes the centralized Ionic Theming system. Global updates should be managed via the theme tokens file, while component-specific overrides are handled through localized CSS variables.
- `--background` is replaced by `IonItemDivider.background` for global styles and `--ion-item-divider-background` for component-specific overrides.
@@ -336,7 +367,7 @@ If you were targeting the internals of `ion-input-otp` in your CSS, you will nee
- `--inner-padding-start` is replaced by `IonItemDivider.inner.padding.start` for global styles and `--ion-item-divider-inner-padding-start` for component-specific overrides.
- Specific theme classes (e.g., `ion-item-divider.md`) are no longer supported. Style modifications based on the active theme must be implemented using theme tokens rather than direct class targeting.
-
Menu Toggle
+
Menu Toggle
The following breaking changes apply to `ion-menu-toggle`:
@@ -346,7 +377,7 @@ The following breaking changes apply to `ion-menu-toggle`:
Remove any instances that target the theme classes: `ion-menu-toggle.md`, `ion-menu-toggle.ios`.
-
Radio Group
+
Radio Group
Converted `ion-radio-group` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).
@@ -354,48 +385,48 @@ If you were targeting the internals of `ion-radio-group` in your CSS, you will n
Additionally, the `radio-group-wrapper` div element has been removed, causing slotted elements to be direct children of the `ion-radio-group`.
-
Ripple Effect
+
Ripple Effect
The following breaking changes apply to `ion-ripple-effect`:
-1. The previously undocumented `--ripple-opacity` CSS variable has been renamed to `--ion-ripple-effect-opacity`. [1](#version-9x-ripple-effect-opacity-variable)
-2. Theme classes (`ion-ripple-effect.md`, `ion-ripple-effect.ios`) are no longer supported. [2](#version-9x-ripple-effect-theme-classes)
+1. The previously undocumented `--ripple-opacity` CSS variable has been renamed to `--ion-ripple-effect-opacity`. [1](#version-10x-ripple-effect-opacity-variable)
+2. Theme classes (`ion-ripple-effect.md`, `ion-ripple-effect.ios`) are no longer supported. [2](#version-10x-ripple-effect-theme-classes)
-
Opacity variable
+
Opacity variable
The ripple fade opacity is now part of the centralized Ionic Theming system. Use the new token structure for global styles, or the corresponding CSS variable for component-specific overrides:
-| Old (8.x) | New token (global) | New CSS variable (component-specific) |
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--ripple-opacity` | `IonRippleEffect.opacity` | `--ion-ripple-effect-opacity` |
-
Theme classes
+
Theme classes
Remove any instances that target the theme classes: `ion-ripple-effect.md`, `ion-ripple-effect.ios`.
-
Row
+
Row
The following breaking changes apply to `ion-row`:
-1. Theme classes (`ion-row.md`, `ion-row.ios`) are no longer supported. [1](#version-9x-row-theme-classes)
+1. Theme classes (`ion-row.md`, `ion-row.ios`) are no longer supported. [1](#version-10x-row-theme-classes)
-
Theme classes
+
Theme classes
Remove any instances that target the theme classes: `ion-row.md`, `ion-row.ios`.
-
Skeleton Text
+
Skeleton Text
The following breaking changes apply to `ion-skeleton-text`:
-1. `--background` and `--background-rgb` CSS variables have been replaced with per-state background tokens, each split into an RGB value and an alpha. [1](#version-9x-skeleton-text-replaced-css-variables)
-2. `--border-radius` has been replaced. [1](#version-9x-skeleton-text-replaced-css-variables)
-3. Theme classes (`ion-skeleton-text.md`, `ion-skeleton-text.ios`) are no longer supported. [2](#version-9x-skeleton-text-theme-classes)
+1. `--background` and `--background-rgb` CSS variables have been replaced with per-state background tokens, each split into an RGB value and an alpha. [1](#version-10x-skeleton-text-replaced-css-variables)
+2. `--border-radius` has been replaced. [1](#version-10x-skeleton-text-replaced-css-variables)
+3. Theme classes (`ion-skeleton-text.md`, `ion-skeleton-text.ios`) are no longer supported. [2](#version-10x-skeleton-text-theme-classes)
-
Replaced CSS variables
+
Replaced CSS variables
The background is now defined per state (resting and animated), and each state exposes an RGB value plus an alpha so the color and its opacity can be set independently. Use the new token structure for global styles, or the corresponding CSS variable for component-specific overrides:
-| Old (8.x) | New token (global) | New CSS variable (component-specific) |
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--background-rgb` | `IonSkeletonText.default.background.rgb` | `--ion-skeleton-text-default-background-rgb` |
| `--background-rgb` | `IonSkeletonText.animated.background.rgb` | `--ion-skeleton-text-animated-background-rgb` |
@@ -406,11 +437,11 @@ The previously fixed opacities are now adjustable through new per-state alpha to
> [!NOTE]
> `--background` (the resting color) has been removed with no one-to-one replacement; set `--ion-skeleton-text-default-background-rgb` (and optionally `--ion-skeleton-text-default-background-alpha`) instead. The single `--background-rgb` variable previously tinted both the resting fill and the animated shimmer. It is now split per state, so set both `--ion-skeleton-text-default-background-rgb` and `--ion-skeleton-text-animated-background-rgb` to recolor both.
-
Theme classes
+
Theme classes
Remove any instances that target the theme classes: `ion-skeleton-text.md`, `ion-skeleton-text.ios`.
-
Spinner
+
Spinner
- Component CSS variables have been removed. The component now utilizes the centralized Ionic Theming system. Global updates should be managed via the theme tokens file, while component-specific overrides are handled through localized CSS variables.
- `--color` is replaced by `IonSpinner.color` for global styles and
@@ -419,7 +450,7 @@ Remove any instances that target the theme classes: `ion-skeleton-text.md`, `ion
- `.spinner-[spinner-name]` β `.spinner-name-[spinner-name]`
- Specific theme classes (e.g., `ion-spinner.md`) are no longer supported. Style modifications based on the active theme must be implemented using theme tokens rather than direct class targeting.
-
Text
+
Text
The following breaking changes apply to `ion-text`:
@@ -441,25 +472,40 @@ When `color` is set, the text color now reads from a token instead of `--ion-col
Remove any instances that target the theme classes: `ion-text.md`, `ion-text.ios`.
-
Textarea
+
Textarea
Converted `ion-textarea` to use [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM).
-If you were targeting the internals of `ion-textarea` in your CSS, you will need to target the `wrapper`, `container`, `label`, `native`, `supporting-text`, `helper-text`, `error-text`, `counter`, or `bottom` [Shadow Parts](https://ionicframework.com/docs/theming/css-shadow-parts) instead, or use the provided CSS Variables.
+If you were targeting the internals of `ion-textarea` in your CSS, you will need to target the `wrapper`, `container`, `label`, `native`, `supporting-text`, `helper-text`, `error-text`, `counter`, `bottom`, `start`, `control`, or `end` [Shadow Parts](https://ionicframework.com/docs/theming/css-shadow-parts) instead, or use the provided CSS Variables.
+
+The internal wrappers that Ionic 9 introduced are no longer reachable as descendants. Slotted content stays in the light DOM, so it is still reachable directly:
+
+```diff
+-ion-textarea .textarea-control .native-wrapper { }
++ion-textarea::part(container) { }
+
+-ion-textarea .textarea-start [slot="start"] { }
++ion-textarea [slot="start"] { }
+
+-ion-textarea .textarea-end [slot="end"] { }
++ion-textarea [slot="end"] { }
+```
+
+To style the wrappers themselves rather than the slotted content, use `part="start"` and `part="end"`.
-
Thumbnail
+
Thumbnail
The following breaking changes apply to `ion-thumbnail`:
-1. `--size` has been split into separate `--ion-thumbnail-width` and `--ion-thumbnail-height` CSS variables. [1](#version-9x-thumbnail-replaced-css-variables)
-2. `--border-radius` has been replaced. [1](#version-9x-thumbnail-replaced-css-variables)
-3. Theme classes (`ion-thumbnail.md`, `ion-thumbnail.ios`) are no longer supported. [2](#version-9x-thumbnail-theme-classes)
+1. `--size` has been split into separate `--ion-thumbnail-width` and `--ion-thumbnail-height` CSS variables. [1](#version-10x-thumbnail-replaced-css-variables)
+2. `--border-radius` has been replaced. [1](#version-10x-thumbnail-replaced-css-variables)
+3. Theme classes (`ion-thumbnail.md`, `ion-thumbnail.ios`) are no longer supported. [2](#version-10x-thumbnail-theme-classes)
-
Replaced CSS variables
+
Replaced CSS variables
`--size` and `--border-radius` have been replaced. Use the new token structure for global styles, or the corresponding CSS variable for component-specific overrides:
-| Old (8.x) | New token (global) | New CSS variable (component-specific) |
+| Old (9.x) | New token (global) | New CSS variable (component-specific) |
|---|---|---|
| `--size` | `IonThumbnail.width` | `--ion-thumbnail-width` |
| `--size` | `IonThumbnail.height` | `--ion-thumbnail-height` |
@@ -468,7 +514,7 @@ The following breaking changes apply to `ion-thumbnail`:
> [!NOTE]
> Code that previously set `--size: 48px` on `ion-thumbnail` must now set both `--ion-thumbnail-width: 48px` and `--ion-thumbnail-height: 48px`.
-
Slotted inside `ion-item` or `ion-item-divider`
+
Slotted inside `ion-item` or `ion-item-divider`
When `ion-thumbnail` is slotted inside a parent component, the parent owns the sizing.
@@ -482,3 +528,32 @@ Use the **parent's** thumbnail tokens instead:
Theme classes
Remove any instances that target the theme classes: `ion-thumbnail.md`, `ion-thumbnail.ios`.
+
+
Framework Specific
+
+
Angular
+
+**Boolean Inputs Are Type Checked**
+
+Boolean inputs now declare an input transform, so attribute presence is an explicitly supported way to set them:
+
+```html
+
+
+
+```
+
+Declaring the transform also makes Angular type check these inputs, which it did not do before. The generated proxies declare no class fields, so Angular had nothing to check a binding against and accepted any value. Bindings that pass a value outside `boolean | string | null | undefined` now fail to compile. The common case is a truthiness binding:
+
+```diff
+-
++ 0">
+```
+
+```
+error TS2322: Type 'number' is not assignable to type 'string | boolean | null | undefined'.
+```
+
+Coerce the expression to a boolean, with an explicit comparison or `!!value`. Bindings that already pass a boolean, a string, `null` or `undefined` are unaffected.
+
+Coercion also moves from Stencil to Angular, which changes the result for numbers. `0` and `NaN` previously became `false` and now become `true`, matching Angular's own `booleanAttribute`. An app without `strictTemplates` gets no compile error for the binding above, so an empty list now renders the item as tappable rather than plain. Coercing the expression fixes both the type error and the runtime change.
diff --git a/BREAKING_ARCHIVE/v9.md b/BREAKING_ARCHIVE/v9.md
new file mode 100644
index 00000000000..6917a36d11b
--- /dev/null
+++ b/BREAKING_ARCHIVE/v9.md
@@ -0,0 +1,700 @@
+# Breaking Changes
+
+## Version 9.x
+
+- [Browser and Platform Support](#version-9x-browser-platform-support)
+- [Package Exports](#version-9x-package-exports)
+- [Components](#version-9x-components)
+ - [Input](#version-9x-input)
+ - [Legacy Picker](#version-9x-legacy-picker)
+ - [Modal](#version-9x-modal)
+ - [Nav](#version-9x-nav)
+ - [Router Outlet](#version-9x-router-outlet)
+ - [Searchbar](#version-9x-searchbar)
+ - [Select](#version-9x-select)
+ - [Textarea](#version-9x-textarea)
+- [Framework Specific](#version-9x-framework-specific)
+ - [Angular](#version-9x-angular)
+ - [React](#version-9x-react)
+ - [Vue](#version-9x-vue)
+
+
Browser and Platform Support
+
+This section details the desktop browser, JavaScript framework, and mobile platform versions that are supported by Ionic 9.
+
+**Minimum Browser Versions**
+| Desktop Browser | Supported Versions |
+| --------------- | ------------------ |
+| Chrome | 89+ |
+| Safari | 16+ |
+| Edge | 89+ |
+| Firefox | 75+ |
+
+**Minimum JavaScript Framework Versions**
+| Framework | Supported Version |
+| --------- | --------------------- |
+| Angular | 18+ |
+| React | 18 or 19 |
+| Vue | 3.5+ |
+
+**Minimum Mobile Platform Versions**
+| Platform | Supported Version |
+| -------- | ---------------------- |
+| iOS | 16+ |
+| Android | 5.1+ with Chromium 89+ |
+
+**Minimum Native Runtime Versions**
+| Native Runtime | Supported Version |
+| -------------- | ----------------- |
+| Capacitor | 7+ |
+
+Ionic's native platform detection no longer checks the Capacitor 2 `isNative` flag. `isCapacitorNative` now relies solely on `Capacitor.isNativePlatform()`, which was added in Capacitor 3. Apps running Capacitor 2 will no longer be detected as a native/hybrid platform, so `isPlatform('capacitor')`, `isPlatform('hybrid')`, and `getPlatforms()` will report web instead of native. Upgrade to a supported Capacitor version (7 or later).
+
+
Package Exports
+
+`@ionic/core`'s `package.json` now declares an `exports` field. Subpaths like `@ionic/core/components` and `@ionic/core/loader` previously failed under Node ESM (Angular 21's default Vitest builder, raw Node, etc.) with `ERR_UNSUPPORTED_DIR_IMPORT`, because the strict ESM resolver doesn't read the nested `package.json` files this package relied on. The new `exports` map declares the documented subpaths explicitly.
+
+`exports` is an allowlist. Apps using Node ESM, webpack 5, or TypeScript `moduleResolution: "bundler"`/`"node16"`/`"nodenext"` that import from undocumented internal paths need to switch to one of the supported subpaths:
+
+| Subpath | Use |
+| ---------------------------------- | ----------------------------------------------------- |
+| `@ionic/core` | Root entry, controllers, animation builders |
+| `@ionic/core/components` | Custom-element constructors and shared utilities |
+| `@ionic/core/components/ion-*.js` | Single-component custom-element constructor |
+| `@ionic/core/loader` | `defineCustomElements` lazy loader |
+| `@ionic/core/hydrate` | SSR hydration entry |
+| `@ionic/core/css/*.css` | Global stylesheets and palettes |
+
+Apps on `moduleResolution: "node"` (classic) and webpack 4 keep resolving through the legacy fields and are unaffected.
+
+
Components
+
+
Input
+
+**`autocorrect` Property Type Changed to Boolean**
+
+The `autocorrect` property on `ion-input` is now a `boolean` and defaults to `false`. It was previously typed as `'on' | 'off'` with a default of `'off'`. This resolves a type conflict introduced when TypeScript 5.9 added `autocorrect: boolean` to the DOM `HTMLElement` interface.
+
+The string form no longer behaves the same way. Because an HTML attribute coerces to `true` for any non-empty string, `autocorrect="off"` now evaluates to `true` (autocorrect enabled). Migrate to the boolean property:
+
+- Remove the attribute to keep autocorrect disabled (the default).
+- Use a property binding to enable it: `[autocorrect]="true"` (Angular), `autocorrect={true}` (React), or `:autocorrect="true"` (Vue).
+
+**Floating Label Behavior**
+
+Floating labels no longer automatically float when the input contains slotted content. Labels float only when the input is focused or has a value.
+
+**Internal DOM Structure Changes**
+
+The internal DOM structure has been reorganized to support floating labels with slotted content.
+
+Added:
+- `.input-start`
+- `.input-control`
+- `.input-end`
+
+Restructured:
+- `.label-text-wrapper` moved from `.input-wrapper` into `.input-control`
+- `.native-wrapper` moved from `.input-wrapper` into `.input-control`
+- Start slot moved from `.native-wrapper` into `.input-start`
+- Clear button icon moved from `.native-wrapper` into `.input-end`
+- End slot moved from `.native-wrapper` into `.input-end`
+- `.input-control` now contains the label text and native `input`, while start/end content is separated into dedicated wrappers
+
+Update your selectors to account for these structural changes:
+
+```diff
+-ion-input .input-wrapper .native-wrapper { }
++ion-input .input-control .native-wrapper { }
+
+-ion-input .input-wrapper .native-wrapper [slot="start"] { }
++ion-input .input-start [slot="start"] { }
+
+-ion-input .input-wrapper .native-wrapper .input-clear-icon { }
++ion-input .input-end .input-clear-icon { }
+
+-ion-input .input-wrapper .native-wrapper [slot="end"] { }
++ion-input .input-end [slot="end"] { }
+```
+
+
Legacy Picker
+
+- `ion-picker-legacy` and `ion-picker-legacy-column` have been removed. The legacy picker component has been replaced with an inline picker component.
+ - Usages such as `ion-picker-legacy` or `IonPickerLegacy` should be changed to `ion-picker` and `IonPicker`, respectively.
+- Remove any usages of `pickerController`. If using React, remove any usages of the `useIonPicker` hook. These controller-based APIs have been removed. Use the inline picker component instead.
+- Remove any usages of the `PickerOptions`, `PickerButton`, `PickerColumn`, and `PickerColumnOption` type exports. These types were associated with the legacy picker and have been removed.
+
+
Modal
+
+The `handleBehavior` property on `ion-modal` now defaults to `"cycle"` instead of `"none"`. For sheet modals that display a handle, this means the handle is now focusable and activating it (by click, keyboard, or screen reader) cycles the sheet through its available breakpoints. This matches the native iOS sheet behavior and keeps sheet modals operable for assistive technology users by default.
+
+Sheet modals that relied on the handle being inert should set `handleBehavior="none"` to restore the previous behavior:
+
+```html
+
+```
+
+
Nav
+
+`ion-nav` no longer integrates with `ion-router`. It is now a standalone imperative stack navigation component, driven only through its own API (`root`, `push`, `pop`, `setRoot`, etc.) and `ion-nav-link`.
+
+The following behaviors have been removed:
+
+- The router no longer discovers or drives an `ion-nav`. Placing an `ion-nav` inside an `ion-router` no longer turns it into a routed outlet.
+- Navigating an `ion-nav` (via `push`, `pop`, `ion-nav-link`, or the swipe-to-go-back gesture) no longer updates the URL, and the router's navigation guards no longer run for `ion-nav` transitions.
+- The internal `setRouteId()` and `getRouteId()` methods and the `updateURL` nav option have been removed.
+
+Apps that relied on `ion-nav` to update the URL (for example, pushing components and expecting the browser URL to change) should use `ion-router-outlet` for URL-based routing. Keep the `ion-route` definitions and swap the outlet element:
+
+```diff
+
+
+
+
+
+-
++
+```
+
+An `ion-nav` can still be used inside a routed page for local, URL-less stack navigation. It manages its own stack via `root` and `ion-nav-link`, and the URL never changes as you push and pop:
+
+```html
+
+
+
+
+```
+
+
Router Outlet
+
+`ion-router-outlet` now exposes a `swipeGesture` property that controls the swipe-to-go-back gesture per outlet. This property defaults to `true` in `"ios"` mode and `false` in `"md"` mode.
+
+**`swipeBackEnabled` Config Behavior Change**
+
+In React and Vue, the `swipeBackEnabled` config option is now read once when the outlet mounts. Apps that dynamically toggle this config value at runtime should migrate to the `swipeGesture` property instead:
+
+**React:**
+
+```diff
+- setupIonicReact({ swipeBackEnabled: someCondition });
++
+```
+
+**Vue:**
+
+```diff
+- createApp(App).use(IonicVue, { swipeBackEnabled: someCondition })
++
+```
+
+**Disabling Swipe-to-Go-Back**
+
+To disable the gesture on a specific outlet, set `swipeGesture` to `false`:
+
+```tsx
+
+```
+
+The `swipeBackEnabled` config option is still respected as the initial default and does not need to change for apps that set it once at startup.
+
+
Searchbar
+
+The `autocorrect` property on `ion-searchbar` is now a `boolean` and defaults to `false`. It was previously typed as `'on' | 'off'` with a default of `'off'`. This resolves a type conflict introduced when TypeScript 5.9 added `autocorrect: boolean` to the DOM `HTMLElement` interface.
+
+The string form no longer behaves the same way. Because an HTML attribute coerces to `true` for any non-empty string, `autocorrect="off"` now evaluates to `true` (autocorrect enabled). Migrate to the boolean property:
+
+- Remove the attribute to keep autocorrect disabled (the default).
+- Use a property binding to enable it: `[autocorrect]="true"` (Angular), `autocorrect={true}` (React), or `:autocorrect="true"` (Vue).
+
+
Select
+
+**`ionChange` Only Fires When the Value Changes**
+
+The `ionChange` event on `ion-select` now only fires when the selected value actually changes. Previously, the `alert` and `action-sheet` interfaces emitted `ionChange` every time the overlay was confirmed, even when the user chose the option that was already selected. This aligns the `alert` and `action-sheet` interfaces with the existing behavior of the `popover` and `modal` interfaces, and with the documented contract of `ionChange`.
+
+Apps that relied on `ionChange` firing on every confirmation (for example, to detect overlay dismissal without a value change) should listen for `ionDismiss` instead, or use the `didDismiss` event on the underlying alert or action sheet.
+
+**Action Sheet Interface `selected` Role Removed**
+
+When using `interface="action-sheet"`, `ion-select` no longer assigns the `selected` role to the action sheet button for the currently selected option. This aligns the `action-sheet` interface with the `alert`, `popover`, and `modal` interfaces, none of which assign this role. This does not change the selected option's styling.
+
+Previously, the `selected` role was assigned only to the option matching the select's current value. Because the dismiss role mirrors the tapped button, this surfaced in just one case: re-selecting the already-selected option dismissed the action sheet with `role: "selected"` in `ionActionSheetDidDismiss`. Tapping any other option changed the value and dismissed with `role: ""`. Now that the role is no longer assigned, both cases dismiss with `role: undefined`. Apps that inspected this role to detect that a value was chosen, such as reading `role` from the underlying action sheet's `onDidDismiss` result, should listen for `ion-select`'s `ionChange` event instead, which emits the selected value when the selection changes.
+
+**Floating Label Behavior**
+
+Floating labels no longer automatically float when the select contains slotted content. Labels float only when the select is focused or has a value. Additionally, when using a floating label, the placeholder is only visible when the select is focused.
+
+**Internal DOM Structure Changes**
+
+The internal DOM structure has been reorganized to support floating labels with slotted content. This changes the structure and location of several exposed shadow parts.
+
+Added:
+- `.select-start` β `part="start"`
+- `.select-control` β `part="control"`
+- `.select-end` β `part="end"`
+
+Removed:
+- `.select-wrapper-inner` β `part="inner"`
+
+Restructured:
+- `.label-text-wrapper` remains `part="label"` but moved from `.select-wrapper` into `.select-control`
+- `.native-wrapper` remains `part="container"` but moved from `.select-wrapper-inner` into `.select-control`
+- Start slot moved from `.select-wrapper-inner` into `.select-start` (`part="start"`)
+- End slot moved from `.select-wrapper-inner` into `.select-end` (`part="end"`)
+- `.select-icon` remains `part="icon"` but its location depends on the label state:
+ - With a start/end label, the icon is inside `.native-wrapper`
+ - With a floating/stacked label, the icon is inside `.select-end`
+
+Update selectors that target the exposed shadow parts to account for the new structure:
+
+If you currently target `part="inner"`, that part has been removed. Update those styles to target the new parts as appropriate.
+
+If you target `part="label"`, `part="container"`, or `part="icon"`, the part names remain unchanged, but their position in the shadow DOM has changed. This may affect styles that depend on the relationship or layout of these parts.
+
+Use the new `part="start"`, `part="control"`, and `part="end"` parts to target the new structural wrappers.
+
+
Textarea
+
+**Floating Label Behavior**
+
+Floating labels no longer automatically float when the textarea contains slotted content. Labels float only when the textarea is focused or has a value.
+
+**Internal DOM Structure Changes**
+
+The internal DOM structure has been reorganized to support floating labels with slotted content.
+
+Removed: `.textarea-wrapper-inner`
+
+Added: `.textarea-control`
+
+Renamed:
+- `.start-slot-wrapper` β `.textarea-start`
+- `.end-slot-wrapper` β `.textarea-end`
+
+Restructured:
+- `.label-text-wrapper` moved from `.textarea-wrapper-inner` into `.textarea-control`
+- `.native-wrapper` moved from `.textarea-wrapper-inner` into `.textarea-control`
+- `.start-slot-wrapper` moved from `.textarea-wrapper-inner` to `.textarea-wrapper` and was renamed `.textarea-start`
+- `.end-slot-wrapper` moved from `.textarea-wrapper-inner` to `.textarea-wrapper` and was renamed `.textarea-end`
+
+Update your selectors to account for these structural changes:
+
+```diff
+-ion-textarea .textarea-wrapper-inner .native-wrapper { }
++ion-textarea .textarea-control .native-wrapper { }
+
+-ion-textarea .start-slot-wrapper [slot="start"] { }
++ion-textarea .textarea-start [slot="start"] { }
+
+-ion-textarea .end-slot-wrapper [slot="end"] { }
++ion-textarea .textarea-end [slot="end"] { }
+```
+
+**Minimum Height Change**
+
+The minimum height of textarea in Material Design (`md` mode) is now `72px`. At the default number of rows this makes textareas the same height regardless of the `fill` property or `labelPlacement`. Previously the minimum height was:
+
+| Fill | Label placement | Previous minimum height |
+| --- | --- | --- |
+| default | `start`, `end`, `fixed` | `44px` |
+| default | `floating`, `stacked` | `56px` |
+| `solid`, `outline` | any | `56px` |
+
+These were minimums, not the heights textareas actually rendered at. A textarea with content in the `start` or `end` slots was already taller than its minimum, so the change affects it differently. For example, a `fill="solid"` textarea with slotted icons and buttons previously rendered at `72px` with a `start` label and `81px` with a `floating` label. Both are now `72px`, so that floating label case is `9px` shorter than before rather than taller.
+
+Because `72px` is taller than two rows of text, `rows` values below `3` no longer change the height of the textarea in `md` mode: `rows="1"` and `rows="2"` both render at `72px`.
+
+If you were relying on the previous heights, or you need `rows` to control the height, override the minimum height back. The override has to be more specific than the component's own style, so a bare `ion-textarea` selector will not apply. Add a custom class to the textarea to increase specificity:
+
+```css
+/* Add a custom class to the textarea */
+ion-textarea.custom {
+ min-height: 44px;
+}
+```
+
+
Framework Specific
+
+
Angular
+
+**Minimum Angular Version**
+
+Ionic 9 requires Angular 18 or later. Angular 16 and 17 are no longer supported.
+
+**Standalone Components Imported by Default**
+
+Following industry standards, Ionic 9 makes standalone components the default import path. Standalone component imports have changed from `@ionic/angular/standalone` to `@ionic/angular`. Lazy-loaded component imports have changed from `@ionic/angular` to `@ionic/angular/lazy`.
+
+**IonicModule Deprecation**
+
+`IonicModule` is deprecated in Ionic 9 and will be removed in a future major version. It remains fully functional in Ionic 9, so existing applications continue to work without changes.
+
+Applications should migrate to `provideIonicAngular()`, which works in both standalone and NgModule-based applications. For an NgModule-based app, replace `IonicModule.forRoot(config)` in the `imports` array with `provideIonicAngular(config)` in the `providers` array. Any config passed to `IonicModule.forRoot()` can be passed as an object to `provideIonicAngular()`. Refer to the [build options guide](https://ionicframework.com/docs/angular/build-options) for migration steps.
+
+**Zoneless Change Detection by Default**
+
+Ionic 9 defaults to zoneless change detection. Angular 21 bootstraps zoneless out of the box, so a new Ionic 9 app on Angular 21 runs without Zone.js and requires no change-detection provider. The `ng add @ionic/angular` schematic no longer registers `provideZoneChangeDetection()`.
+
+Because Zone.js no longer triggers change detection automatically, component state that you update from an asynchronous callback that Angular doesn't wrap (awaiting an overlay result such as `modal.onWillDismiss()`, `setTimeout`, RxJS subscriptions, `Platform` events) no longer re-renders on its own. Update a signal or call `ChangeDetectorRef.markForCheck()` in those callbacks. Template event bindings, `@HostListener`, reactive forms, and Ionic lifecycle hooks (`ionViewWillEnter`, etc.) that set state synchronously are unaffected. Refer to the [Zoneless Change Detection guide](https://ionicframework.com/docs/angular/zoneless) for the patterns.
+
+On Angular 18 through 20, Zone.js remains Angular's default, so those versions are unaffected and require no change. To adopt zoneless there, add `provideZonelessChangeDetection()` (named `provideExperimentalZonelessChangeDetection()` on Angular 18 and 19).
+
+**Keeping Zone.js on Angular 21 (optional)**
+
+To keep using Zone.js on Angular 21, opt back in with `provideZoneChangeDetection()` and keep `zone.js` in your polyfills.
+
+Standalone bootstrap:
+
+```diff
+ import { bootstrapApplication } from '@angular/platform-browser';
++ import { provideZoneChangeDetection } from '@angular/core';
+
+ bootstrapApplication(AppComponent, {
+ providers: [
++ provideZoneChangeDetection(),
+ // ...other providers
+ ],
+ });
+```
+
+NgModule bootstrap:
+
+```diff
+ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
++ import { provideZoneChangeDetection } from '@angular/core';
+
+ platformBrowserDynamic()
+- .bootstrapModule(AppModule)
++ .bootstrapModule(AppModule, {
++ applicationProviders: [provideZoneChangeDetection()],
++ })
+ .catch((err) => console.error(err));
+```
+
+Angular forbids `provideZoneChangeDetection()` inside an NgModule's `providers` array, so for NgModule apps it must be passed as `applicationProviders` on the `bootstrapModule()` call. Both paths also require `zone.js` in your polyfills, which Angular 21's default scaffold omits:
+
+```ts
+// src/polyfills.ts
+import 'zone.js';
+```
+
+**OnPush by Default on Angular 22**
+
+Angular 22 changes the default change detection strategy to `OnPush` for components that don't declare one. Combined with the zoneless default above, any component state that you mutate as a plain field from an Ionic lifecycle hook (`ionViewWillEnter`, etc.) no longer re-renders on its own. Run `ng update`, which migrates existing components to eager change detection and preserves the previous behavior, or use a signal (or `ChangeDetectorRef.markForCheck()`) for state set in those hooks. Ionic's own Angular components already declare `OnPush` explicitly and are unaffected. Angular 18 through 21 keep the eager default, so they require no change.
+
+**TypeScript**
+
+Ionic 9 supports TypeScript 5.4 or later, matching the minimum for Angular 18. Angular 21 requires TypeScript 5.9 or later, and Angular 22 requires TypeScript 6.0 or later, per Angular's own requirements.
+
+**Node.js**
+
+Angular 22 raises the minimum Node.js version to `^22.22.3 || ^24.15.0 || ^26.0.0`. Angular 18 through 21 are unaffected.
+
+**Module Resolution**
+
+`@ionic/angular` is now published with `exports`-based subpath resolution. Apps using TypeScript `moduleResolution: "node"` (classic) can fail to resolve subpaths such as `@ionic/angular/lazy`. Set `moduleResolution` to `"bundler"` (the default for `ng new` on Angular 17 and later). Refer to [Package Exports](#version-9x-package-exports).
+
+**CSS Imports No Longer Use the `~` Prefix**
+
+Angular's current build pipeline no longer supports the webpack-loader `~` prefix in CSS `@import` statements:
+
+```diff
+- @import '~@ionic/angular/css/core.css';
++ @import '@ionic/angular/css/core.css';
+```
+
+
React
+
+The `@ionic/react` and `@ionic/react-router` packages now require React 18 or 19. React 17 is no longer supported.
+
+The `@ionic/react-router` package now requires React Router v6. React Router v5 is no longer supported.
+
+**Minimum Version Requirements**
+| Package | Supported Version |
+| ---------------- | ----------------- |
+| react | 18 or 19 |
+| react-dom | 18 or 19 |
+| react-router | 6.4.0+ |
+| react-router-dom | 6.4.0+ |
+
+**TypeScript**
+
+The `@ionic/react` package now requires TypeScript 5.4 or later. Its type definitions use `NoInfer`, which TypeScript added in 5.4. This matches the minimum that `@ionic/angular` already requires.
+
+**Typed Overlay Hook Props**
+
+The `useIonModal` and `useIonPopover` hooks type `componentProps` against the component they are given, instead of accepting `any`. Props that do not match the component are a compile error, and `componentProps` is required when the component declares required props. Applications passing incorrect props will see new type errors at build time rather than failing at runtime.
+
+```diff
+ const Modal: React.FC<{ title: string }> = ({ title }) => {title};
+
+- const [present, dismiss] = useIonModal(Modal, { subtitle: 'Wrong' });
++ const [present, dismiss] = useIonModal(Modal, { title: 'Hello' });
+```
+
+Props are read from the component rather than from `componentProps`, so a component declared inline needs its props annotated:
+
+```diff
+- const [present, dismiss] = useIonModal(({ name }) =>
, { name: 'Dave' });
+```
+
+Passing a JSX element rather than a component is unchanged, and `componentProps` is not type checked in that case.
+
+`npx @ionic/migrate` reports the calls this affects and names what is wrong with each, but does not rewrite them, since the right fix depends on what the call was meant to do. For the inline case above, `--experimental` can annotate the parameter from the `componentProps` object literal being passed.
+
+React Router v6 introduces several API changes that will require updates to your application's routing configuration:
+
+**Route Definition Changes**
+
+The `component` prop has been replaced with the `element` prop, which accepts JSX:
+
+```diff
+-
++ } />
+```
+
+**Redirect Changes**
+
+The `` component has been replaced with ``:
+
+```diff
+- import { Redirect } from 'react-router-dom';
++ import { Navigate } from 'react-router-dom';
+
+-
++
+```
+
+**Nested Route Paths**
+
+Routes that contain nested routes or child `IonRouterOutlet` components need a `/*` suffix to match sub-paths:
+
+```diff
+- } />
++ } />
+```
+
+**Accessing Route Parameters**
+
+Route parameters are now accessed via the `useParams` hook instead of props:
+
+```diff
+- import { RouteComponentProps } from 'react-router-dom';
++ import { useParams } from 'react-router-dom';
+
+- const MyComponent: React.FC> = ({ match }) => {
+- const id = match.params.id;
++ const MyComponent: React.FC = () => {
++ const { id } = useParams<{ id: string }>();
+```
+
+**RouteComponentProps Removed**
+
+The `RouteComponentProps` type and its `history`, `location`, and `match` props are no longer available in React Router v6. Use the equivalent hooks instead:
+
+- `history` -> `useNavigate` (see below) or `useIonRouter`
+- `match.params` -> `useParams` (covered above)
+- `location` -> `useLocation`
+
+```diff
+- import { RouteComponentProps } from 'react-router-dom';
++ import { useNavigate, useLocation } from 'react-router-dom';
++ import { useIonRouter } from '@ionic/react';
+
+- const MyComponent: React.FC = ({ history, location }) => {
+- history.push('/path');
+- history.replace('/path');
+- history.goBack();
+- console.log(location.pathname);
++ const MyComponent: React.FC = () => {
++ const navigate = useNavigate();
++ const router = useIonRouter();
++ const location = useLocation();
++ // In an event handler or useEffect:
++ navigate('/path');
++ navigate('/path', { replace: true });
++ router.goBack();
++ console.log(location.pathname);
+```
+
+**Exact Prop Removed**
+
+The `exact` prop is no longer needed. React Router v6 routes match exactly by default. To match sub-paths, use a `/*` suffix on the path:
+
+```diff
+-
++
+```
+
+**Render Prop Removed**
+
+The `render` prop has been replaced with the `element` prop:
+
+```diff
+- } />
++ } />
+```
+
+**Programmatic Navigation**
+
+The `useHistory` hook has been replaced with `useNavigate`:
+
+```diff
+- import { useHistory } from 'react-router-dom';
++ import { useNavigate } from 'react-router-dom';
++ import { useIonRouter } from '@ionic/react';
+
+- const history = useHistory();
++ const navigate = useNavigate();
++ const router = useIonRouter();
+
+- history.push('/path');
++ navigate('/path');
+
+- history.replace('/path');
++ navigate('/path', { replace: true });
+
+- history.goBack();
++ router.goBack();
+```
+
+**Custom History Prop Removed**
+
+The `history` prop has been removed from `IonReactRouter`, `IonReactHashRouter`, and `IonReactMemoryRouter`. React Router v6's `BrowserRouter`, `HashRouter`, and `MemoryRouter` no longer accept custom `history` objects.
+
+```diff
+- import { createBrowserHistory } from 'history';
+- const history = createBrowserHistory();
+-
++
+```
+
+For `IonReactMemoryRouter` (commonly used in tests), use `initialEntries` instead:
+
+```diff
+- import { createMemoryHistory } from 'history';
+- const history = createMemoryHistory({ initialEntries: ['/start'] });
+-
++
+```
+
+**IonRedirect Removed**
+
+The `IonRedirect` component has been removed. Use React Router's `` component instead:
+
+```diff
+- import { IonRedirect } from '@ionic/react';
+-
++ import { Navigate } from 'react-router-dom';
++ } />
+```
+
+**Path Regex Constraints Removed**
+
+React Router v6 no longer supports regex constraints in path parameters (e.g., `/:tab(sessions)`). Use literal paths instead:
+
+```diff
+-
+-
++ } />
++ } />
+```
+
+**IonRoute API Changes**
+
+The `IonRoute` component follows the same API changes as React Router's ``. The `render` prop has been replaced with `element`, and the `exact` prop has been removed:
+
+```diff
+- } />
++ } />
+```
+
+For more information on migrating from React Router v5 to v6, refer to the [React Router v6 Upgrade Guide](https://reactrouter.com/6.28.0/upgrading/v5).
+
+
diff --git a/core/scripts/verify/lazy-imports.js b/core/scripts/verify/lazy-imports.js
new file mode 100644
index 00000000000..d0008130474
--- /dev/null
+++ b/core/scripts/verify/lazy-imports.js
@@ -0,0 +1,56 @@
+/**
+ * Fails if the built lazy loader is missing a literal import path for any component bundle.
+ * Not in `scripts/testing/` because `vercel-build.sh` publishes that directory.
+ * https://github.com/ionic-team/ionic-framework/issues/31333
+ */
+const fs = require('fs');
+const path = require('path');
+
+const PACKAGE_ROOT = path.resolve(__dirname, '..', '..');
+const OUTPUT_DIRS = ['dist/esm', 'dist/cjs'];
+
+function main() {
+ const failures = OUTPUT_DIRS.map(verify).filter((message) => message !== null);
+
+ if (failures.length > 0) {
+ failures.forEach((message) => console.error(message));
+ process.exit(1);
+ }
+
+ console.error(`Success! Every lazy bundle is imported by path in ${OUTPUT_DIRS.join(' and ')}`);
+}
+
+function verify(dir) {
+ const resolved = path.join(PACKAGE_ROOT, dir);
+
+ if (!fs.existsSync(resolved)) {
+ return `${dir} does not exist. Run npm run build first.`;
+ }
+
+ const files = fs.readdirSync(resolved).filter((file) => file.endsWith('.js'));
+ const entries = files.filter((file) => file.endsWith('.entry.js'));
+
+ if (entries.length === 0) {
+ return `${dir} does not contain any .entry.js files.`;
+ }
+
+ // A non-loader chunk that happens to name an entry file would be a false pass.
+ const loader = files
+ .filter((file) => !file.endsWith('.entry.js'))
+ .map((file) => fs.readFileSync(path.join(resolved, file), 'utf-8'))
+ .find((source) => /switch\s*\(bundleId\)/.test(source));
+
+ if (loader === undefined) {
+ return `${dir} has no lazy loader with a bundle id switch. Check that extras.enableImportInjection is still set in core/stencil.config.ts.`;
+ }
+
+ const missing = entries.filter((entry) => !loader.includes(`'./${entry}'`) && !loader.includes(`"./${entry}"`));
+
+ if (missing.length > 0) {
+ return `${dir} is missing an import for ${missing.length} of ${entries.length} lazy bundles: ${missing.join(', ')}`;
+ }
+
+ return null;
+}
+
+main();
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index 661ab287668..a25784da787 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -18,8 +18,10 @@ import { BreadcrumbCollapsedClickEventDetail } from "./components/breadcrumb/bre
import { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interface";
import { IonChipFill, IonChipShape, IonChipSize } from "./components/chip/chip.interfaces";
import { ScrollBaseDetail, ScrollDetail } from "./components/content/content.interfaces";
-import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimePresentation, FormatOptions, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
+import { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimeParts, DatetimePresentation, FormatOptions, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
+import { FooterScrollEffect } from "./components/footer/footer-interface";
import { GalleryColumns, GalleryGap } from "./components/gallery/gallery-interface";
+import { HeaderScrollEffect } from "./components/header/header-interface";
import { SpinnerTypes } from "./components/spinner/spinner-configs";
import { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface";
import { InputOtpChangeEventDetail, InputOtpCompleteEventDetail, InputOtpInputEventDetail } from "./components/input-otp/input-otp-interface";
@@ -29,7 +31,6 @@ import { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, S
import { ViewController } from "./components/nav/view-controller";
import { PickerChangeEventDetail } from "./components/picker/picker-interfaces";
import { PickerColumnChangeEventDetail, PickerColumnValue } from "./components/picker-column/picker-column-interfaces";
-import { PickerButton, PickerColumn } from "./components/picker-legacy/picker-interface";
import { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from "./components/popover/popover-interface";
import { IonProgressBarShape } from "./components/progress-bar/progress-bar.interfaces";
import { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
@@ -46,7 +47,7 @@ import { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./com
import { SelectModalOption } from "./components/select-modal/select-modal-interface";
import { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
import { SpinnerSize } from "./components/spinner/spinner.interfaces";
-import { TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
+import { TabBarChangedEventDetail, TabBarScrollEffect, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
import { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface";
import { ToastButton, ToastDismissOptions, ToastLayout, ToastPosition, ToastPresentOptions, ToastSwipeGestureDirection } from "./components/toast/toast-interface";
import { ToggleChangeEventDetail } from "./components/toggle/toggle-interface";
@@ -63,8 +64,10 @@ export { BreadcrumbCollapsedClickEventDetail } from "./components/breadcrumb/bre
export { CheckboxChangeEventDetail } from "./components/checkbox/checkbox-interface";
export { IonChipFill, IonChipShape, IonChipSize } from "./components/chip/chip.interfaces";
export { ScrollBaseDetail, ScrollDetail } from "./components/content/content.interfaces";
-export { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimePresentation, FormatOptions, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
+export { DatetimeChangeEventDetail, DatetimeHighlight, DatetimeHighlightCallback, DatetimeHourCycle, DatetimeParts, DatetimePresentation, FormatOptions, TitleSelectedDatesFormatter } from "./components/datetime/datetime-interface";
+export { FooterScrollEffect } from "./components/footer/footer-interface";
export { GalleryColumns, GalleryGap } from "./components/gallery/gallery-interface";
+export { HeaderScrollEffect } from "./components/header/header-interface";
export { SpinnerTypes } from "./components/spinner/spinner-configs";
export { InputChangeEventDetail, InputInputEventDetail } from "./components/input/input-interface";
export { InputOtpChangeEventDetail, InputOtpCompleteEventDetail, InputOtpInputEventDetail } from "./components/input-otp/input-otp-interface";
@@ -74,7 +77,6 @@ export { NavComponent, NavComponentWithProps, NavOptions, RouterOutletOptions, S
export { ViewController } from "./components/nav/view-controller";
export { PickerChangeEventDetail } from "./components/picker/picker-interfaces";
export { PickerColumnChangeEventDetail, PickerColumnValue } from "./components/picker-column/picker-column-interfaces";
-export { PickerButton, PickerColumn } from "./components/picker-legacy/picker-interface";
export { PopoverSize, PositionAlign, PositionReference, PositionSide, TriggerAction } from "./components/popover/popover-interface";
export { IonProgressBarShape } from "./components/progress-bar/progress-bar.interfaces";
export { RadioGroupChangeEventDetail, RadioGroupCompareFn } from "./components/radio-group/radio-group-interface";
@@ -91,7 +93,7 @@ export { SelectChangeEventDetail, SelectCompareFn, SelectInterface } from "./com
export { SelectModalOption } from "./components/select-modal/select-modal-interface";
export { SelectPopoverOption } from "./components/select-popover/select-popover-interface";
export { SpinnerSize } from "./components/spinner/spinner.interfaces";
-export { TabBarChangedEventDetail, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
+export { TabBarChangedEventDetail, TabBarScrollEffect, TabButtonClickEventDetail, TabButtonLayout } from "./components/tab-bar/tab-bar-interface";
export { TextareaChangeEventDetail, TextareaInputEventDetail } from "./components/textarea/textarea-interface";
export { ToastButton, ToastDismissOptions, ToastLayout, ToastPosition, ToastPresentOptions, ToastSwipeGestureDirection } from "./components/toast/toast-interface";
export { ToggleChangeEventDetail } from "./components/toggle/toggle-interface";
@@ -1078,7 +1080,7 @@ export namespace Components {
*/
"mode"?: "ios" | "md";
/**
- * Recalculate content dimensions. Called by overlays (e.g., popover) when sibling elements like headers or footers have finished rendering and their heights are available, ensuring accurate offset-top calculations.
+ * Recalculates the content dimensions and whether it should size itself to its content. Called by overlays when something they own changes, such as a header finishing its render or `--height` being updated.
*/
"recalculateDimensions": () => Promise;
/**
@@ -1138,8 +1140,7 @@ export namespace Components {
*/
"clearText": string;
/**
- * The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
- * @default 'primary'
+ * The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, refer to [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
@@ -1170,6 +1171,10 @@ export namespace Components {
* Formatting options for dates and times. Should include a 'date' and/or 'time' object, each of which is of type [Intl.DateTimeFormatOptions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#options).
*/
"formatOptions"?: FormatOptions;
+ /**
+ * Returns the default parts the datetime falls back to when no value is set: today's date and time snapped to the closest value allowed by the component's constraints (`min`, `max`, and the `*Values` props).
+ */
+ "getDefaultPart": () => Promise;
/**
* Used to apply custom text and background colors to specific dates. Can be either an array of objects containing ISO strings and colors, or a callback that receives an ISO string and returns the colors. Only applies to the `date`, `date-time`, and `time-date` presentations, with `preferWheel="false"`.
*/
@@ -1291,7 +1296,6 @@ export namespace Components {
interface IonDatetimeButton {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
- * @default 'primary'
*/
"color"?: Color;
/**
@@ -1383,6 +1387,10 @@ export namespace Components {
* This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want).
*/
"download": string | undefined;
+ /**
+ * The HTML form element or form element id. Used to submit a form when the button is not a child of the form.
+ */
+ "form"?: string | HTMLFormElement;
/**
* Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered.
*/
@@ -1455,12 +1463,17 @@ export namespace Components {
interface IonFooter {
/**
* Describes the scroll effect that will be applied to the footer. Only applies when the theme is `"ios"`.
+ * @deprecated Use `scrollEffect` instead.
*/
"collapse"?: 'fade';
/**
* The mode determines the platform behaviors of the component.
*/
"mode"?: "ios" | "md";
+ /**
+ * Describes the scroll effect that will be applied to the footer. `"hide"` slides the footer out of view when scrolling down and back in when scrolling up. `"fade"` fades the toolbar background on scroll.
+ */
+ "scrollEffect"?: FooterScrollEffect;
/**
* The theme determines the visual appearance of the component.
*/
@@ -1528,6 +1541,7 @@ export namespace Components {
interface IonHeader {
/**
* Describes the scroll effect that will be applied to the header. Only applies when the theme is `"ios"`. Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
+ * @deprecated Use `scrollEffect` instead.
*/
"collapse"?: 'condense' | 'fade';
/**
@@ -1539,6 +1553,10 @@ export namespace Components {
* The mode determines the platform behaviors of the component.
*/
"mode"?: "ios" | "md";
+ /**
+ * Describes the scroll effect that will be applied to the header. `"hide"` slides the header out of view when scrolling down and back in when scrolling up. `"condense"` collapses the large title into the main toolbar on scroll. `"fade"` fades the toolbar background on scroll.
+ */
+ "scrollEffect"?: HeaderScrollEffect;
/**
* The theme determines the visual appearance of the component.
*/
@@ -1628,9 +1646,9 @@ export namespace Components {
"autocomplete": AutocompleteTypes;
/**
* Whether auto correction should be enabled when the user is entering/editing the text value.
- * @default 'off'
+ * @default false
*/
- "autocorrect": 'on' | 'off';
+ "autocorrect": boolean;
/**
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element. This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
* @default false
@@ -2430,8 +2448,8 @@ export namespace Components {
*/
"handle"?: boolean;
/**
- * The interaction behavior for the sheet modal when the handle is pressed. Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed. Set to `"cycle"` to let the modal cycle between available breakpoints when pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal).
- * @default 'none'
+ * The interaction behavior for the sheet modal when the handle is pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal). Set to `"cycle"` to make the handle focusable and let the sheet modal cycle between available breakpoints when pressed. This keeps the sheet operable with assistive technology. Set to `"none"` to make the handle purely decorative when pressed and removed from the tab order. Defaults to `"cycle"`.
+ * @default 'cycle'
*/
"handleBehavior"?: ModalHandleBehavior;
/**
@@ -2543,10 +2561,6 @@ export namespace Components {
* @param view The view to get.
*/
"getPrevious": (view?: ViewController) => Promise;
- /**
- * Called by to retrieve the current component.
- */
- "getRouteId": () => Promise;
/**
* Inserts a component into the navigation stack at the specified index. This is useful to add a component at any point in the navigation stack.
* @param insertIndex The index to insert the component at in the stack.
@@ -2626,15 +2640,6 @@ export namespace Components {
* @param done The transition complete function.
*/
"setRoot": (component: T, componentProps?: ComponentProps | null, opts?: NavOptions | null, done?: TransitionDoneFn) => Promise;
- /**
- * Called by the router to update the view.
- * @param id The component tag.
- * @param params The component params.
- * @param direction A direction hint.
- * @param animation an AnimationBuilder.
- * @return the status.
- */
- "setRouteId": (id: string, params: ComponentProps | undefined, direction: RouterDirection, animation?: AnimationBuilder) => Promise;
/**
* If the nav component should allow for swipe-to-go-back.
*/
@@ -2699,7 +2704,6 @@ export namespace Components {
interface IonPickerColumn {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
- * @default 'primary'
*/
"color"?: Color;
/**
@@ -2737,7 +2741,6 @@ export namespace Components {
interface IonPickerColumnOption {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
- * @default 'primary'
*/
"color"?: Color;
/**
@@ -2758,111 +2761,6 @@ export namespace Components {
*/
"value"?: any | null;
}
- interface IonPickerLegacy {
- /**
- * If `true`, the picker will animate.
- * @default true
- */
- "animated": boolean;
- /**
- * If `true`, the picker will be dismissed when the backdrop is clicked.
- * @default true
- */
- "backdropDismiss": boolean;
- /**
- * Array of buttons to be displayed at the top of the picker.
- * @default []
- */
- "buttons": PickerButton[];
- /**
- * Array of columns to be displayed in the picker.
- * @default []
- */
- "columns": PickerColumn[];
- /**
- * Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces.
- */
- "cssClass"?: string | string[];
- "delegate"?: FrameworkDelegate;
- /**
- * Dismiss the picker overlay after it has been presented.
- * @param data Any data to emit in the dismiss events.
- * @param role The role of the element that is dismissing the picker. This can be useful in a button handler for determining which button was clicked to dismiss the picker. Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
- */
- "dismiss": (data?: any, role?: string) => Promise;
- /**
- * Number of milliseconds to wait before dismissing the picker.
- * @default 0
- */
- "duration": number;
- /**
- * Animation to use when the picker is presented.
- */
- "enterAnimation"?: AnimationBuilder;
- /**
- * Get the column that matches the specified name.
- * @param name The name of the column.
- */
- "getColumn": (name: string) => Promise;
- /**
- * @default false
- */
- "hasController": boolean;
- /**
- * Additional attributes to pass to the picker.
- */
- "htmlAttributes"?: { [key: string]: any };
- /**
- * If `true`, the picker will open. If `false`, the picker will close. Use this if you need finer grained control over presentation, otherwise just use the pickerController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the picker dismisses. You will need to do that in your code.
- * @default false
- */
- "isOpen": boolean;
- /**
- * If `true`, the keyboard will be automatically dismissed when the overlay is presented.
- * @default true
- */
- "keyboardClose": boolean;
- /**
- * Animation to use when the picker is dismissed.
- */
- "leaveAnimation"?: AnimationBuilder;
- /**
- * The mode determines the platform behaviors of the component.
- */
- "mode"?: "ios" | "md";
- /**
- * Returns a promise that resolves when the picker did dismiss.
- */
- "onDidDismiss": () => Promise>;
- /**
- * Returns a promise that resolves when the picker will dismiss.
- */
- "onWillDismiss": () => Promise>;
- "overlayIndex": number;
- /**
- * Present the picker overlay after it has been created.
- */
- "present": () => Promise;
- /**
- * If `true`, a backdrop will be displayed behind the picker.
- * @default true
- */
- "showBackdrop": boolean;
- /**
- * The theme determines the visual appearance of the component.
- */
- "theme"?: "ios" | "md" | "ionic";
- /**
- * An ID corresponding to the trigger element that causes the picker to open when clicked.
- */
- "trigger": string | undefined;
- }
- interface IonPickerLegacyColumn {
- /**
- * Picker column data
- */
- "col": PickerColumn;
- }
interface IonPopover {
/**
* Describes how to align the popover content with the `reference` point. Defaults to `"center"` for `"ios"` theme, and `"start"` for `"md"` theme.
@@ -3148,7 +3046,7 @@ export namespace Components {
*/
"disabled": boolean;
/**
- * Show two knobs.
+ * If `true`, the range shows two knobs and `value` is an object with `lower` and `upper` properties. If `false`, the range shows one knob and `value` is a number.
* @default false
*/
"dualKnobs": boolean;
@@ -3350,7 +3248,7 @@ export namespace Components {
*/
"beforeLeave"?: NavigationHookCallback;
/**
- * Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-nav`) when the route matches. The value of this property is not always the tagname of the component to load, in `ion-tabs` it actually refers to the name of the `ion-tab` to select.
+ * Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-router-outlet`) when the route matches. The value of this property is not always the tagname of the component to load, in `ion-tabs` it actually refers to the name of the `ion-tab` to select.
*/
"component": string;
/**
@@ -3467,8 +3365,12 @@ export namespace Components {
* The mode determines the platform behaviors of the component.
* @default getIonMode(this)
*/
- "mode": "md" | "ios";
+ "mode": "ios" | "md";
"setRouteId": (id: string, params: ComponentProps | undefined, direction: RouterDirection, animation?: AnimationBuilder) => Promise;
+ /**
+ * If `true`, the router-outlet should allow navigation via swipe-to-go-back gesture. Defaults to `true` for `"ios"` mode and `false` for `"md"` mode.
+ */
+ "swipeGesture"?: boolean;
"swipeHandler"?: SwipeGestureHandler;
/**
* The theme determines the visual appearance of the component.
@@ -3499,9 +3401,9 @@ export namespace Components {
"autocomplete": AutocompleteTypes;
/**
* Set the input's autocorrect property.
- * @default 'off'
+ * @default false
*/
- "autocorrect": 'on' | 'off';
+ "autocorrect": boolean;
/**
* Set the cancel button icon. Only available when the theme is `"md"`. Defaults to `"arrow-back-sharp"`.
*/
@@ -3845,7 +3747,7 @@ export namespace Components {
*/
"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.
+ * If `true`, the user cannot interact with the select option.
* @default false
*/
"disabled": boolean;
@@ -3997,15 +3899,14 @@ export namespace Components {
* @default 'full'
*/
"expand": 'compact' | 'full';
- /**
- * If `true`, the tab bar will be hidden when the user scrolls down and shown when the user scrolls up. Only applies when the theme is `"ionic"` and `expand` is `"compact"`.
- * @default false
- */
- "hideOnScroll": boolean;
/**
* The mode determines the platform behaviors of the component.
*/
"mode"?: "ios" | "md";
+ /**
+ * Describes the scroll effect that will be applied to the tab bar. `"hide"` slides the tab bar out of view when scrolling down and back in when scrolling up. Note: `"hide"` is ignored when the tab bar is nested inside an `ion-footer` to avoid leaving an empty footer visible on screen. Set `scroll-effect="hide"` on the footer instead so the entire footer hides together.
+ */
+ "scrollEffect"?: TabBarScrollEffect;
/**
* The selected tab component
*/
@@ -4589,14 +4490,6 @@ export interface IonPickerColumnCustomEvent extends CustomEvent {
detail: T;
target: HTMLIonPickerColumnElement;
}
-export interface IonPickerLegacyCustomEvent extends CustomEvent {
- detail: T;
- target: HTMLIonPickerLegacyElement;
-}
-export interface IonPickerLegacyColumnCustomEvent extends CustomEvent {
- detail: T;
- target: HTMLIonPickerLegacyColumnElement;
-}
export interface IonPopoverCustomEvent extends CustomEvent {
detail: T;
target: HTMLIonPopoverElement;
@@ -5372,47 +5265,6 @@ declare global {
prototype: HTMLIonPickerColumnOptionElement;
new (): HTMLIonPickerColumnOptionElement;
};
- interface HTMLIonPickerLegacyElementEventMap {
- "ionPickerDidPresent": void;
- "ionPickerWillPresent": void;
- "ionPickerWillDismiss": OverlayEventDetail;
- "ionPickerDidDismiss": OverlayEventDetail;
- "didPresent": void;
- "willPresent": void;
- "willDismiss": OverlayEventDetail;
- "didDismiss": OverlayEventDetail;
- }
- interface HTMLIonPickerLegacyElement extends Components.IonPickerLegacy, HTMLStencilElement {
- addEventListener(type: K, listener: (this: HTMLIonPickerLegacyElement, ev: IonPickerLegacyCustomEvent) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
- removeEventListener(type: K, listener: (this: HTMLIonPickerLegacyElement, ev: IonPickerLegacyCustomEvent) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
- }
- var HTMLIonPickerLegacyElement: {
- prototype: HTMLIonPickerLegacyElement;
- new (): HTMLIonPickerLegacyElement;
- };
- interface HTMLIonPickerLegacyColumnElementEventMap {
- "ionPickerColChange": PickerColumn;
- }
- interface HTMLIonPickerLegacyColumnElement extends Components.IonPickerLegacyColumn, HTMLStencilElement {
- addEventListener(type: K, listener: (this: HTMLIonPickerLegacyColumnElement, ev: IonPickerLegacyColumnCustomEvent) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
- addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
- removeEventListener(type: K, listener: (this: HTMLIonPickerLegacyColumnElement, ev: IonPickerLegacyColumnCustomEvent) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
- removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
- }
- var HTMLIonPickerLegacyColumnElement: {
- prototype: HTMLIonPickerLegacyColumnElement;
- new (): HTMLIonPickerLegacyColumnElement;
- };
interface HTMLIonPopoverElementEventMap {
"ionPopoverDidPresent": void;
"ionPopoverWillPresent": void;
@@ -6013,8 +5865,6 @@ declare global {
"ion-picker": HTMLIonPickerElement;
"ion-picker-column": HTMLIonPickerColumnElement;
"ion-picker-column-option": HTMLIonPickerColumnOptionElement;
- "ion-picker-legacy": HTMLIonPickerLegacyElement;
- "ion-picker-legacy-column": HTMLIonPickerLegacyColumnElement;
"ion-popover": HTMLIonPopoverElement;
"ion-progress-bar": HTMLIonProgressBarElement;
"ion-radio": HTMLIonRadioElement;
@@ -6057,7 +5907,7 @@ declare global {
}
}
declare namespace LocalJSX {
- type OneOf = { [P in K]: PropT } & { [P in `attr:${K}` | `prop:${K}`]?: never } | { [P in `attr:${K}`]: AttrT } & { [P in K | `prop:${K}`]?: never } | { [P in `prop:${K}`]: PropT } & { [P in K | `attr:${K}`]?: never };
+ type OneOf = { [P in K]: PropT } & { [P in `attr:${K}`]?: never } | { [P in `attr:${K}`]: AttrT } & { [P in K]?: never };
interface IonAccordion {
/**
@@ -7137,8 +6987,7 @@ declare namespace LocalJSX {
*/
"clearText"?: string;
/**
- * The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
- * @default 'primary'
+ * The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, refer to [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
@@ -7308,7 +7157,6 @@ declare namespace LocalJSX {
interface IonDatetimeButton {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
- * @default 'primary'
*/
"color"?: Color;
/**
@@ -7392,6 +7240,10 @@ declare namespace LocalJSX {
* This attribute instructs browsers to download a URL instead of navigating to it, so the user will be prompted to save it as a local file. If the attribute has a value, it is used as the pre-filled file name in the Save prompt (the user can still change the file name if they want).
*/
"download"?: string | undefined;
+ /**
+ * The HTML form element or form element id. Used to submit a form when the button is not a child of the form.
+ */
+ "form"?: string | HTMLFormElement;
/**
* Contains a URL or a URL fragment that the hyperlink points to. If this property is set, an anchor tag will be rendered.
*/
@@ -7472,12 +7324,17 @@ declare namespace LocalJSX {
interface IonFooter {
/**
* Describes the scroll effect that will be applied to the footer. Only applies when the theme is `"ios"`.
+ * @deprecated Use `scrollEffect` instead.
*/
"collapse"?: 'fade';
/**
* The mode determines the platform behaviors of the component.
*/
"mode"?: "ios" | "md";
+ /**
+ * Describes the scroll effect that will be applied to the footer. `"hide"` slides the footer out of view when scrolling down and back in when scrolling up. `"fade"` fades the toolbar background on scroll.
+ */
+ "scrollEffect"?: FooterScrollEffect;
/**
* The theme determines the visual appearance of the component.
*/
@@ -7541,6 +7398,7 @@ declare namespace LocalJSX {
interface IonHeader {
/**
* Describes the scroll effect that will be applied to the header. Only applies when the theme is `"ios"`. Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
+ * @deprecated Use `scrollEffect` instead.
*/
"collapse"?: 'condense' | 'fade';
/**
@@ -7552,6 +7410,10 @@ declare namespace LocalJSX {
* The mode determines the platform behaviors of the component.
*/
"mode"?: "ios" | "md";
+ /**
+ * Describes the scroll effect that will be applied to the header. `"hide"` slides the header out of view when scrolling down and back in when scrolling up. `"condense"` collapses the large title into the main toolbar on scroll. `"fade"` fades the toolbar background on scroll.
+ */
+ "scrollEffect"?: HeaderScrollEffect;
/**
* The theme determines the visual appearance of the component.
*/
@@ -7653,9 +7515,9 @@ declare namespace LocalJSX {
"autocomplete"?: AutocompleteTypes;
/**
* Whether auto correction should be enabled when the user is entering/editing the text value.
- * @default 'off'
+ * @default false
*/
- "autocorrect"?: 'on' | 'off';
+ "autocorrect"?: boolean;
/**
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element. This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
* @default false
@@ -8469,8 +8331,8 @@ declare namespace LocalJSX {
*/
"handle"?: boolean;
/**
- * The interaction behavior for the sheet modal when the handle is pressed. Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed. Set to `"cycle"` to let the modal cycle between available breakpoints when pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal).
- * @default 'none'
+ * The interaction behavior for the sheet modal when the handle is pressed. Handle behavior is unavailable when the `handle` property is set to `false` or when the `breakpoints` property is not set (using a fullscreen or card modal). Set to `"cycle"` to make the handle focusable and let the sheet modal cycle between available breakpoints when pressed. This keeps the sheet operable with assistive technology. Set to `"none"` to make the handle purely decorative when pressed and removed from the tab order. Defaults to `"cycle"`.
+ * @default 'cycle'
*/
"handleBehavior"?: ModalHandleBehavior;
/**
@@ -8682,7 +8544,6 @@ declare namespace LocalJSX {
interface IonPickerColumn {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
- * @default 'primary'
*/
"color"?: Color;
/**
@@ -8715,7 +8576,6 @@ declare namespace LocalJSX {
interface IonPickerColumnOption {
/**
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
- * @default 'primary'
*/
"color"?: Color;
/**
@@ -8736,124 +8596,6 @@ declare namespace LocalJSX {
*/
"value"?: any | null;
}
- interface IonPickerLegacy {
- /**
- * If `true`, the picker will animate.
- * @default true
- */
- "animated"?: boolean;
- /**
- * If `true`, the picker will be dismissed when the backdrop is clicked.
- * @default true
- */
- "backdropDismiss"?: boolean;
- /**
- * Array of buttons to be displayed at the top of the picker.
- * @default []
- */
- "buttons"?: PickerButton[];
- /**
- * Array of columns to be displayed in the picker.
- * @default []
- */
- "columns"?: PickerColumn[];
- /**
- * Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces.
- */
- "cssClass"?: string | string[];
- "delegate"?: FrameworkDelegate;
- /**
- * Number of milliseconds to wait before dismissing the picker.
- * @default 0
- */
- "duration"?: number;
- /**
- * Animation to use when the picker is presented.
- */
- "enterAnimation"?: AnimationBuilder;
- /**
- * @default false
- */
- "hasController"?: boolean;
- /**
- * Additional attributes to pass to the picker.
- */
- "htmlAttributes"?: { [key: string]: any };
- /**
- * If `true`, the picker will open. If `false`, the picker will close. Use this if you need finer grained control over presentation, otherwise just use the pickerController or the `trigger` property. Note: `isOpen` will not automatically be set back to `false` when the picker dismisses. You will need to do that in your code.
- * @default false
- */
- "isOpen"?: boolean;
- /**
- * If `true`, the keyboard will be automatically dismissed when the overlay is presented.
- * @default true
- */
- "keyboardClose"?: boolean;
- /**
- * Animation to use when the picker is dismissed.
- */
- "leaveAnimation"?: AnimationBuilder;
- /**
- * The mode determines the platform behaviors of the component.
- */
- "mode"?: "ios" | "md";
- /**
- * Emitted after the picker has dismissed. Shorthand for ionPickerDidDismiss.
- */
- "onDidDismiss"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted after the picker has presented. Shorthand for ionPickerWillDismiss.
- */
- "onDidPresent"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted after the picker has dismissed.
- */
- "onIonPickerDidDismiss"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted after the picker has presented.
- */
- "onIonPickerDidPresent"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted before the picker has dismissed.
- */
- "onIonPickerWillDismiss"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted before the picker has presented.
- */
- "onIonPickerWillPresent"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted before the picker has dismissed. Shorthand for ionPickerWillDismiss.
- */
- "onWillDismiss"?: (event: IonPickerLegacyCustomEvent) => void;
- /**
- * Emitted before the picker has presented. Shorthand for ionPickerWillPresent.
- */
- "onWillPresent"?: (event: IonPickerLegacyCustomEvent) => void;
- "overlayIndex": number;
- /**
- * If `true`, a backdrop will be displayed behind the picker.
- * @default true
- */
- "showBackdrop"?: boolean;
- /**
- * The theme determines the visual appearance of the component.
- */
- "theme"?: "ios" | "md" | "ionic";
- /**
- * An ID corresponding to the trigger element that causes the picker to open when clicked.
- */
- "trigger"?: string | undefined;
- }
- interface IonPickerLegacyColumn {
- /**
- * Picker column data
- */
- "col": PickerColumn;
- /**
- * Emitted when the selected value has changed
- */
- "onIonPickerColChange"?: (event: IonPickerLegacyColumnCustomEvent) => void;
- }
interface IonPopover {
/**
* Describes how to align the popover content with the `reference` point. Defaults to `"center"` for `"ios"` theme, and `"start"` for `"md"` theme.
@@ -9162,7 +8904,7 @@ declare namespace LocalJSX {
*/
"disabled"?: boolean;
/**
- * Show two knobs.
+ * If `true`, the range shows two knobs and `value` is an object with `lower` and `upper` properties. If `false`, the range shows one knob and `value` is a number.
* @default false
*/
"dualKnobs"?: boolean;
@@ -9403,7 +9145,7 @@ declare namespace LocalJSX {
*/
"beforeLeave"?: NavigationHookCallback;
/**
- * Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-nav`) when the route matches. The value of this property is not always the tagname of the component to load, in `ion-tabs` it actually refers to the name of the `ion-tab` to select.
+ * Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-router-outlet`) when the route matches. The value of this property is not always the tagname of the component to load, in `ion-tabs` it actually refers to the name of the `ion-tab` to select.
*/
"component": string;
/**
@@ -9520,10 +9262,14 @@ declare namespace LocalJSX {
* The mode determines the platform behaviors of the component.
* @default getIonMode(this)
*/
- "mode"?: "md" | "ios";
+ "mode"?: "ios" | "md";
"onIonNavDidChange"?: (event: IonRouterOutletCustomEvent) => void;
"onIonNavWillChange"?: (event: IonRouterOutletCustomEvent) => void;
"onIonNavWillLoad"?: (event: IonRouterOutletCustomEvent) => void;
+ /**
+ * If `true`, the router-outlet should allow navigation via swipe-to-go-back gesture. Defaults to `true` for `"ios"` mode and `false` for `"md"` mode.
+ */
+ "swipeGesture"?: boolean;
"swipeHandler"?: SwipeGestureHandler;
/**
* The theme determines the visual appearance of the component.
@@ -9554,9 +9300,9 @@ declare namespace LocalJSX {
"autocomplete"?: AutocompleteTypes;
/**
* Set the input's autocorrect property.
- * @default 'off'
+ * @default false
*/
- "autocorrect"?: 'on' | 'off';
+ "autocorrect"?: boolean;
/**
* Set the cancel button icon. Only available when the theme is `"md"`. Defaults to `"arrow-back-sharp"`.
*/
@@ -9949,7 +9695,7 @@ declare namespace LocalJSX {
*/
"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.
+ * If `true`, the user cannot interact with the select option.
* @default false
*/
"disabled"?: boolean;
@@ -10104,17 +9850,16 @@ declare namespace LocalJSX {
* @default 'full'
*/
"expand"?: 'compact' | 'full';
- /**
- * If `true`, the tab bar will be hidden when the user scrolls down and shown when the user scrolls up. Only applies when the theme is `"ionic"` and `expand` is `"compact"`.
- * @default false
- */
- "hideOnScroll"?: boolean;
/**
* The mode determines the platform behaviors of the component.
*/
"mode"?: "ios" | "md";
"onIonTabBarChanged"?: (event: IonTabBarCustomEvent) => void;
"onIonTabBarLoaded"?: (event: IonTabBarCustomEvent) => void;
+ /**
+ * Describes the scroll effect that will be applied to the tab bar. `"hide"` slides the tab bar out of view when scrolling down and back in when scrolling up. Note: `"hide"` is ignored when the tab bar is nested inside an `ion-footer` to avoid leaving an empty footer visible on screen. Set `scroll-effect="hide"` on the footer instead so the entire footer hides together.
+ */
+ "scrollEffect"?: TabBarScrollEffect;
/**
* The selected tab component
*/
@@ -10896,6 +10641,7 @@ declare namespace LocalJSX {
"show": boolean;
"translucent": boolean;
"type": 'submit' | 'reset' | 'button';
+ "form": string | HTMLFormElement;
"size": 'small';
"closeIcon": string;
}
@@ -10904,6 +10650,7 @@ declare namespace LocalJSX {
"side": 'start' | 'end' | 'top' | 'bottom';
}
interface IonFooterAttributes {
+ "scrollEffect": FooterScrollEffect;
"collapse": 'fade';
"translucent": boolean;
}
@@ -10917,6 +10664,7 @@ declare namespace LocalJSX {
"fixed": boolean;
}
interface IonHeaderAttributes {
+ "scrollEffect": HeaderScrollEffect;
"collapse": 'condense' | 'fade';
"divider": boolean;
"translucent": boolean;
@@ -10939,7 +10687,7 @@ declare namespace LocalJSX {
"color": Color;
"autocapitalize": string;
"autocomplete": AutocompleteTypes;
- "autocorrect": 'on' | 'off';
+ "autocorrect": boolean;
"autofocus": boolean;
"clearInput": boolean;
"clearInputIcon": string;
@@ -11120,18 +10868,6 @@ declare namespace LocalJSX {
"value": string;
"color": Color;
}
- interface IonPickerLegacyAttributes {
- "overlayIndex": number;
- "hasController": boolean;
- "keyboardClose": boolean;
- "cssClass": string | string[];
- "duration": number;
- "showBackdrop": boolean;
- "backdropDismiss": boolean;
- "animated": boolean;
- "isOpen": boolean;
- "trigger": string | undefined;
- }
interface IonPopoverAttributes {
"hasController": boolean;
"overlayIndex": number;
@@ -11238,15 +10974,16 @@ declare namespace LocalJSX {
"target": string | undefined;
}
interface IonRouterOutletAttributes {
- "mode": "md" | "ios";
+ "mode": "ios" | "md";
"animated": boolean;
+ "swipeGesture": boolean;
}
interface IonSearchbarAttributes {
"color": Color;
"animated": boolean;
"autocapitalize": string;
"autocomplete": AutocompleteTypes;
- "autocorrect": 'on' | 'off';
+ "autocorrect": boolean;
"cancelButtonIcon": string;
"cancelButtonText": string;
"clearIcon": string;
@@ -11354,7 +11091,7 @@ declare namespace LocalJSX {
interface IonTabBarAttributes {
"color": Color;
"selectedTab": string;
- "hideOnScroll": boolean;
+ "scrollEffect": TabBarScrollEffect;
"translucent": boolean;
"expand": 'compact' | 'full';
"shape": 'soft' | 'round' | 'rectangular';
@@ -11511,8 +11248,6 @@ declare namespace LocalJSX {
"ion-picker": IonPicker;
"ion-picker-column": Omit & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes]?: IonPickerColumn[K] } & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes as `attr:${K}`]?: IonPickerColumnAttributes[K] } & { [K in keyof IonPickerColumn & keyof IonPickerColumnAttributes as `prop:${K}`]?: IonPickerColumn[K] };
"ion-picker-column-option": Omit & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes]?: IonPickerColumnOption[K] } & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes as `attr:${K}`]?: IonPickerColumnOptionAttributes[K] } & { [K in keyof IonPickerColumnOption & keyof IonPickerColumnOptionAttributes as `prop:${K}`]?: IonPickerColumnOption[K] };
- "ion-picker-legacy": Omit & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes]?: IonPickerLegacy[K] } & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes as `attr:${K}`]?: IonPickerLegacyAttributes[K] } & { [K in keyof IonPickerLegacy & keyof IonPickerLegacyAttributes as `prop:${K}`]?: IonPickerLegacy[K] } & OneOf<"overlayIndex", IonPickerLegacy["overlayIndex"], IonPickerLegacyAttributes["overlayIndex"]>;
- "ion-picker-legacy-column": IonPickerLegacyColumn;
"ion-popover": Omit & { [K in keyof IonPopover & keyof IonPopoverAttributes]?: IonPopover[K] } & { [K in keyof IonPopover & keyof IonPopoverAttributes as `attr:${K}`]?: IonPopoverAttributes[K] } & { [K in keyof IonPopover & keyof IonPopoverAttributes as `prop:${K}`]?: IonPopover[K] } & OneOf<"overlayIndex", IonPopover["overlayIndex"], IonPopoverAttributes["overlayIndex"]>;
"ion-progress-bar": Omit & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes]?: IonProgressBar[K] } & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes as `attr:${K}`]?: IonProgressBarAttributes[K] } & { [K in keyof IonProgressBar & keyof IonProgressBarAttributes as `prop:${K}`]?: IonProgressBar[K] };
"ion-radio": Omit & { [K in keyof IonRadio & keyof IonRadioAttributes]?: IonRadio[K] } & { [K in keyof IonRadio & keyof IonRadioAttributes as `attr:${K}`]?: IonRadioAttributes[K] } & { [K in keyof IonRadio & keyof IonRadioAttributes as `prop:${K}`]?: IonRadio[K] };
@@ -11617,8 +11352,6 @@ declare module "@stencil/core" {
"ion-picker": LocalJSX.IntrinsicElements["ion-picker"] & JSXBase.HTMLAttributes;
"ion-picker-column": LocalJSX.IntrinsicElements["ion-picker-column"] & JSXBase.HTMLAttributes;
"ion-picker-column-option": LocalJSX.IntrinsicElements["ion-picker-column-option"] & JSXBase.HTMLAttributes;
- "ion-picker-legacy": LocalJSX.IntrinsicElements["ion-picker-legacy"] & JSXBase.HTMLAttributes;
- "ion-picker-legacy-column": LocalJSX.IntrinsicElements["ion-picker-legacy-column"] & JSXBase.HTMLAttributes;
"ion-popover": LocalJSX.IntrinsicElements["ion-popover"] & JSXBase.HTMLAttributes;
"ion-progress-bar": LocalJSX.IntrinsicElements["ion-progress-bar"] & JSXBase.HTMLAttributes;
"ion-radio": LocalJSX.IntrinsicElements["ion-radio"] & JSXBase.HTMLAttributes;
diff --git a/core/src/components/accordion-group/accordion-group.ionic.scss b/core/src/components/accordion-group/accordion-group.ionic.scss
index 8d4495a6147..99312fe8db3 100644
--- a/core/src/components/accordion-group/accordion-group.ionic.scss
+++ b/core/src/components/accordion-group/accordion-group.ionic.scss
@@ -19,19 +19,19 @@
}
:host(.accordion-group-expand-inset.accordion-group-shape-round) {
- --border-radius: #{globals.$ion-round-xl};
+ --border-radius: #{globals.$ion-shape-round-xl};
- @include globals.border-radius(globals.$ion-round-xl);
+ @include globals.border-radius(globals.$ion-shape-round-xl);
}
:host(.accordion-group-expand-inset.accordion-group-shape-soft) {
- --border-radius: #{globals.$ion-soft-xl};
+ --border-radius: #{globals.$ion-shape-soft-xl};
- @include globals.border-radius(globals.$ion-soft-xl);
+ @include globals.border-radius(globals.$ion-shape-soft-xl);
}
:host(.accordion-group-expand-inset.accordion-group-shape-rectangular) {
- --border-radius: #{globals.$ion-rectangular-xl};
+ --border-radius: #{globals.$ion-shape-rectangular-xl};
- @include globals.border-radius(globals.$ion-rectangular-xl);
+ @include globals.border-radius(globals.$ion-shape-rectangular-xl);
}
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 3fce761ee2c..dd04531ef7d 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 1d1ab6ec0aa..cc0ffe710a0 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Safari-linux.png
index 3f7ceeeaed2..0767252c319 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-expanded-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Chrome-linux.png
index cef9f546adb..adfe984e89f 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 589022e296a..5ebca269e25 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Safari-linux.png
index b4a912ee323..11e5fb7b5c3 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-compact-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 14d4329a95c..54ed08b1dbc 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Firefox-linux.png
index a925225677b..9fb3129f880 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Safari-linux.png
index 67f7f10764d..e8a0b2ec488 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-expanded-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Chrome-linux.png
index d80a088ae2d..a81c63bc868 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Firefox-linux.png
index f56169eb633..2af8c80e706 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Safari-linux.png
index 9b2f7acfdd5..dd387f6f0c5 100644
Binary files a/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion-group/test/expand/accordion-group.e2e.ts-snapshots/accordion-group-expand-inset-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png
index d342fabe6b1..8747f15770b 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png
index aa2de569a9c..74235842362 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png
index 0fb90605bd7..fc460ccb801 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 1a8d5c00709..54ed08b1dbc 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 03bb7b1d6e6..9fb3129f880 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png
index f349a6bf812..e8a0b2ec488 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png
index b581d65cf42..8e8788ba1a6 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 4f9bf1d155d..9fb3129f880 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png
index cef15798fbe..e8a0b2ec488 100644
Binary files a/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion-group/test/shape/accordion-group.e2e.ts-snapshots/accordion-group-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png
index d00f2f7c63b..6e5ffd1c45b 100644
Binary files a/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 76ad15af97a..8ece8681d26 100644
Binary files a/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png
index f593bcbef93..b8eef8fc612 100644
Binary files a/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion-group/test/states/accordion-group.e2e.ts-snapshots/accordion-group-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/accordion.tsx b/core/src/components/accordion/accordion.tsx
index dcfa11029ac..87a475d9afe 100644
--- a/core/src/components/accordion/accordion.tsx
+++ b/core/src/components/accordion/accordion.tsx
@@ -1,4 +1,3 @@
-import caretDownRegular from '@phosphor-icons/core/assets/regular/caret-down.svg';
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';
import { addEventListener, getElementRoot, raf, removeEventListener, transitionEndAsync } from '@utils/helpers';
@@ -242,25 +241,19 @@ export class Accordion implements ComponentInterface {
button.setAttribute('aria-expanded', `${expanded}`);
};
- get accordionToggleIcon() {
+ /**
+ * Get the icon to use for the toggle icon.
+ * If an icon is set on the component, use that.
+ * Otherwise, use the icon set in the config.
+ * If no icon is set in the config, use the default icon.
+ */
+ get accordionToggleIcon(): string {
// Return the icon if it is explicitly set
if (this.toggleIcon != null) {
return this.toggleIcon;
}
- // Determine the theme and map to default icons
- const theme = getIonTheme(this);
- const defaultIcons = {
- ios: chevronDown,
- ionic: caretDownRegular,
- md: chevronDown,
- };
-
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
-
- // Return the configured accordion toggle icon or the default icon
- return config.get('accordionToggleIcon', defaultIcon);
+ return config.get('accordionToggleIcon', chevronDown);
}
private slotToggleIcon = () => {
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Chrome-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Chrome-linux.png
index 9453467642d..836e2cca2c1 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Firefox-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Firefox-linux.png
index f4a0511dce0..53124bc3aee 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Safari-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Safari-linux.png
index 8d312c5f0e0..227d9fb95e2 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Safari-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Chrome-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Chrome-linux.png
index dac7aa36332..121d2dd16ca 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Firefox-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Firefox-linux.png
index a3887543f84..0198077466a 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Safari-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Safari-linux.png
index 8eab5d49de3..df1da9e3380 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Safari-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-md-rtl-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 3fce761ee2c..dd04531ef7d 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 1d1ab6ec0aa..cc0ffe710a0 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Safari-linux.png
index 3f7ceeeaed2..0767252c319 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Chrome-linux.png
index 82c1a08d3fc..5300bcecda0 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 895e3adb2c0..18b375b7fd1 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Safari-linux.png
index 9c2f6a4e70b..9aecbdfa216 100644
Binary files a/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/basic/accordion.e2e.ts-snapshots/accordion-basic-text-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/basic/index.html b/core/src/components/accordion/test/basic/index.html
index 0307c164aa3..a2471ee4c34 100644
--- a/core/src/components/accordion/test/basic/index.html
+++ b/core/src/components/accordion/test/basic/index.html
@@ -34,7 +34,7 @@
-
+ Accordion - Basic
diff --git a/core/src/components/accordion/test/disabled/index.html b/core/src/components/accordion/test/disabled/index.html
index 38452b7adec..af59083c859 100644
--- a/core/src/components/accordion/test/disabled/index.html
+++ b/core/src/components/accordion/test/disabled/index.html
@@ -25,7 +25,7 @@
-
+ Accordion - Disabled
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Chrome-linux.png
index affcb48df2c..46da6ac38a9 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 0c1f394093f..e20979d8058 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Safari-linux.png
index 0d5255f1479..a054aabd705 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-one-open-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 63db497757f..20348a2fa93 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 6ce667543e4..d23dbc459b4 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Safari-linux.png
index ab4afebbfd5..76da7a349bf 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-two-open-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 2f593a98948..eb1a791751f 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Firefox-linux.png
index cc6982c98f5..9c61f1a50fa 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Safari-linux.png
index 79e449fc562..66935e8c295 100644
Binary files a/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/multiple/accordion.e2e.ts-snapshots/accordion-zero-open-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png
index cc2226f4a90..70dbcbe5ec5 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 0d328069396..44916bab85d 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png
index f8ed9c2213a..999c86c68ee 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-child-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 8673bcdbc3f..9d238bafc32 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Firefox-linux.png
index ce47f8aa1f5..4ab0241d0ad 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Safari-linux.png
index 31fc3ef83e7..78a5b8e62e7 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-nested-enabled-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 8c81ad2e667..0d04749b131 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 9dad80dbbf9..b1bd66dcbf7 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png
index 55e81d2a158..2e9375e9149 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-md-ltr-Mobile-Chrome-linux.png b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-md-ltr-Mobile-Chrome-linux.png
index 09d83694f60..e89c97ef2bc 100644
Binary files a/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/nested/accordion.e2e.ts-snapshots/accordion-parent-disabled-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/nested/index.html b/core/src/components/accordion/test/nested/index.html
index 783740c6634..3e4e01a8c89 100644
--- a/core/src/components/accordion/test/nested/index.html
+++ b/core/src/components/accordion/test/nested/index.html
@@ -34,7 +34,7 @@
-
+ Accordion - Basic
diff --git a/core/src/components/accordion/test/readonly/index.html b/core/src/components/accordion/test/readonly/index.html
index 7b1a9ac84c6..43288c7a848 100644
--- a/core/src/components/accordion/test/readonly/index.html
+++ b/core/src/components/accordion/test/readonly/index.html
@@ -25,7 +25,7 @@
-
+ Accordion - Readonly
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 94ba19e0e4f..a167086732c 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png
index a65be70f432..8172cfed8a3 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png
index 49c01b2e47e..7dc34e9d03f 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 351361ad92c..3f3cbccbf2a 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png
index f36d468975e..1bba43fbe88 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png
index 478b85a354e..214fae8d87a 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png
index d71c207ed84..25011f8a4f7 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 83fffaddae6..278048bf450 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png
index 4efe485a8e5..f0bf525f5df 100644
Binary files a/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/shape/accordion.e2e.ts-snapshots/accordion-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 671932d1f35..7ec8b6b96fb 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 943c6cbbbd4..dbb35ed21e4 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Safari-linux.png
index a7a0a26aae7..7ef530055e6 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-activated-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png
index b476b09786b..d21f1b092f4 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 2858c29a81f..8e304c04eeb 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png
index 053fd55e44a..19d33b30828 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Chrome-linux.png
index ca491a09b4d..04fe1e753be 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 4c5626e7d14..0198378a4fc 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Safari-linux.png
index f54c4ab7067..7144d25c388 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-focused-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Chrome-linux.png
index b04e932d7f7..0e5a0ba0e94 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Firefox-linux.png
index f833cdb192f..988353d847e 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Safari-linux.png
index 48113b5086c..5d51a84a6b4 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-activated-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png
index d93df496d35..30859e877b0 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 788ab06f987..ab69d6511b4 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png
index 996184bd208..02245c5aec8 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-disabled-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Chrome-linux.png
index bd196cc78ab..27e69ad1c0e 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 360c619d551..6a780f9edff 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Safari-linux.png
index 112d83b5fe9..861bcefc019 100644
Binary files a/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/accordion/test/states/accordion.e2e.ts-snapshots/accordion-states-inset-focused-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/action-sheet/action-sheet.ionic.scss b/core/src/components/action-sheet/action-sheet.ionic.scss
index 14f12768d9e..bdf890d597a 100644
--- a/core/src/components/action-sheet/action-sheet.ionic.scss
+++ b/core/src/components/action-sheet/action-sheet.ionic.scss
@@ -28,11 +28,7 @@
}
.action-sheet-button.ion-focused::after {
- @include globals.focused-state(
- globals.$ion-border-size-050,
- globals.$ion-border-style-solid,
- globals.$ion-border-focus-default
- );
+ @include globals.focused-state(globals.$ion-border-size-050, solid, globals.$ion-border-focus-default);
outline-offset: calc(globals.$ion-border-size-050 * -1);
}
diff --git a/core/src/components/action-sheet/action-sheet.tsx b/core/src/components/action-sheet/action-sheet.tsx
index 1a4922f5746..35ad13737d9 100644
--- a/core/src/components/action-sheet/action-sheet.tsx
+++ b/core/src/components/action-sheet/action-sheet.tsx
@@ -6,6 +6,7 @@ import { raf } from '@utils/helpers';
import { createLockController } from '@utils/lock-controller';
import {
BACKDROP,
+ cleanupRootFocusTrapAccessibility,
createDelegateController,
createTriggerController,
dismiss,
@@ -13,6 +14,7 @@ import {
isCancel,
prepareOverlay,
present,
+ restoreRootFocusTrapAccessibility,
safeCall,
setOverlayId,
} from '@utils/overlays';
@@ -456,6 +458,15 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
connectedCallback() {
prepareOverlay(this.el);
this.triggerChanged();
+
+ // `componentDidLoad` only fires once per instance, so a reconnect has to
+ // rebuild the gesture its disconnect destroyed.
+ this.setupButtonActiveGesture();
+
+ // Re-apply the root lock if moved without dismiss() being called
+ if (this.presented) {
+ restoreRootFocusTrapAccessibility(this.el);
+ }
}
disconnectedCallback() {
@@ -464,6 +475,11 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
this.gesture = undefined;
}
this.triggerController.removeClickListener();
+
+ // Clean up aria-hidden if removed without dismiss() being called
+ if (this.presented) {
+ cleanupRootFocusTrapAccessibility();
+ }
}
componentWillLoad() {
@@ -474,27 +490,36 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
this.buttonsChanged();
}
- componentDidLoad() {
- const mode = getIonMode(this);
- /**
- * Only create gesture if:
- * 1. A gesture does not already exist
- * 2. App is running in iOS mode
- * 3. A wrapper ref exists
- * 4. A group ref exists
- */
+ /**
+ * Only create gesture if:
+ * 1. A gesture does not already exist
+ * 2. App is running in iOS mode
+ * 3. A wrapper ref exists
+ * 4. A group ref exists
+ * 5. The host is still connected, since a reconnect can schedule this and
+ * disconnect again before the task runs
+ */
+ private setupButtonActiveGesture() {
const { groupEl, wrapperEl } = this;
- if (!this.gesture && mode === 'ios' && wrapperEl && groupEl) {
- readTask(() => {
- const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
- if (!isScrollable) {
- this.gesture = createButtonActiveGesture(wrapperEl, (refEl: HTMLElement) =>
- refEl.classList.contains('action-sheet-button')
- );
- this.gesture.enable(true);
- }
- });
+ if (getIonMode(this) !== 'ios' || !wrapperEl || !groupEl) {
+ return;
}
+ readTask(() => {
+ // Bail if a call queued ahead of this one already built the gesture
+ // (a second would orphan the first with its listeners still bound), if
+ // the host disconnected while this task waited, or if the group scrolls.
+ if (this.gesture || !this.el.isConnected || groupEl.scrollHeight > groupEl.clientHeight) {
+ return;
+ }
+ this.gesture = createButtonActiveGesture(wrapperEl, (refEl: HTMLElement) =>
+ refEl.classList.contains('action-sheet-button')
+ );
+ this.gesture.enable(true);
+ });
+ }
+
+ componentDidLoad() {
+ this.setupButtonActiveGesture();
/**
* If action sheet was rendered with isOpen="true"
diff --git a/core/src/components/action-sheet/test/basic/action-sheet.e2e.ts b/core/src/components/action-sheet/test/basic/action-sheet.e2e.ts
index d0921d354da..19368dd652f 100644
--- a/core/src/components/action-sheet/test/basic/action-sheet.e2e.ts
+++ b/core/src/components/action-sheet/test/basic/action-sheet.e2e.ts
@@ -1,5 +1,5 @@
import { expect } from '@playwright/test';
-import { configs, test } from '@utils/test/playwright';
+import { configs, detachAndReattach, test } from '@utils/test/playwright';
import { ActionSheetFixture } from './fixture';
@@ -166,3 +166,56 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
});
});
});
+
+/**
+ * The button gesture only exists in iOS mode, so these run there.
+ */
+configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ config, title }) => {
+ test.describe(title('action sheet: moved while presented'), () => {
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/src/components/action-sheet/test/basic', config);
+ });
+
+ test('should keep the app root locked', async ({ page }, testInfo) => {
+ testInfo.annotations.push({
+ type: 'issue',
+ description: 'https://github.com/ionic-team/ionic-framework/issues/31389',
+ });
+
+ const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');
+
+ await page.click('#basic');
+ await ionActionSheetDidPresent.next();
+
+ await expect(page.locator('body')).toHaveClass(/backdrop-no-scroll/);
+
+ await detachAndReattach(page.locator('ion-action-sheet'));
+
+ await expect(page.locator('body')).toHaveClass(/backdrop-no-scroll/);
+ });
+
+ test('should keep activating buttons on press', async ({ page }, testInfo) => {
+ testInfo.annotations.push({
+ type: 'issue',
+ description: 'https://github.com/ionic-team/ionic-framework/issues/31389',
+ });
+
+ const ionActionSheetDidPresent = await page.spyOnEvent('ionActionSheetDidPresent');
+
+ await page.click('#basic');
+ await ionActionSheetDidPresent.next();
+
+ await detachAndReattach(page.locator('ion-action-sheet'));
+
+ const button = page.locator('ion-action-sheet .action-sheet-button').first();
+ const box = (await button.boundingBox())!;
+
+ await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
+ await page.mouse.down();
+
+ await expect(button).toHaveClass(/ion-activated/);
+
+ await page.mouse.up();
+ });
+ });
+});
diff --git a/core/src/components/alert/alert.ionic.scss b/core/src/components/alert/alert.ionic.scss
index 3b41ed3928b..714b0321246 100644
--- a/core/src/components/alert/alert.ionic.scss
+++ b/core/src/components/alert/alert.ionic.scss
@@ -23,19 +23,11 @@
}
.alert-button.ion-focused {
- @include globals.focused-state(
- globals.$ion-border-size-050,
- globals.$ion-border-style-solid,
- globals.$ion-border-focus-default
- );
+ @include globals.focused-state(globals.$ion-border-size-050, solid, globals.$ion-border-focus-default);
}
.alert-tappable.ion-focused {
- @include globals.focused-state(
- globals.$ion-border-size-050,
- globals.$ion-border-style-solid,
- globals.$ion-border-focus-default
- );
+ @include globals.focused-state(globals.$ion-border-size-050, solid, globals.$ion-border-focus-default);
outline-offset: calc(globals.$ion-border-size-050 * -1);
}
@@ -106,7 +98,7 @@
.alert-input {
@include mixins.margin(globals.$ion-space-150, 0);
- border-bottom: globals.$ion-border-size-025 globals.$ion-border-style-solid globals.$ion-border-input-default;
+ border-bottom: globals.$ion-border-size-025 solid globals.$ion-border-input-default;
color: globals.$ion-text-default;
@@ -125,7 +117,7 @@
.alert-input:focus {
@include mixins.margin(null, null, globals.$ion-scale-100, null);
- border-bottom: globals.$ion-border-size-050 globals.$ion-border-style-solid globals.$ion-border-focus-default;
+ border-bottom: globals.$ion-border-size-050 solid globals.$ion-border-focus-default;
}
// Ionic Alert Radio/Checkbox Group
@@ -135,8 +127,8 @@
.alert-checkbox-group {
position: relative;
- border-top: globals.$ion-border-size-025 globals.$ion-border-style-solid globals.$ion-border-default;
- border-bottom: globals.$ion-border-size-025 globals.$ion-border-style-solid globals.$ion-border-default;
+ border-top: globals.$ion-border-size-025 solid globals.$ion-border-default;
+ border-bottom: globals.$ion-border-size-025 solid globals.$ion-border-default;
overflow: auto;
}
@@ -210,7 +202,7 @@
height: globals.$ion-scale-600;
border-width: globals.$ion-border-size-025;
- border-style: globals.$ion-border-style-solid;
+ border-style: solid;
border-color: globals.$ion-border-input-default;
background-color: globals.$ion-bg-input-default;
@@ -298,7 +290,7 @@
height: globals.$ion-scale-600;
border-width: globals.$ion-border-size-025;
- border-style: globals.$ion-border-style-solid;
+ border-style: solid;
border-color: globals.$ion-primitives-neutral-800;
background-color: globals.$ion-bg-input-default;
@@ -316,15 +308,6 @@
@include globals.position-horizontal(null, globals.$ion-space-400);
}
-.alert-checkbox-inner {
- width: globals.$ion-scale-400;
- height: globals.$ion-scale-400;
-}
-
-.alert-checkbox-inner path {
- fill: globals.$ion-bg-surface-default;
-}
-
// Ionic Alert Checkbox Checkmark: Checked
// --------------------------------------------------
@@ -334,6 +317,19 @@
background-color: globals.$ion-bg-primary-base-default;
}
+// The checkmark is a box clipped to the outline of the mark ion-checkbox
+// draws. It represents a two-segment polyline with a 3-unit stroke in a
+// 24-unit box. The polygon points trace the outer and inner edges of that
+// stroke and are derived from the checkmark's geometry.
+[aria-checked="true"] .alert-checkbox-inner {
+ width: globals.$ion-scale-400;
+ height: globals.$ion-scale-400;
+
+ background-color: globals.$ion-bg-surface-default;
+
+ clip-path: polygon(2.79% 58.21%, 33.75% 89.17%, 99.38% 23.54%, 90.54% 14.71%, 33.75% 71.49%, 11.63% 49.37%);
+}
+
// Ionic Alert Button
// --------------------------------------------------
diff --git a/core/src/components/alert/alert.tsx b/core/src/components/alert/alert.tsx
index 44adc065aa9..6fcc9e3063c 100644
--- a/core/src/components/alert/alert.tsx
+++ b/core/src/components/alert/alert.tsx
@@ -8,14 +8,16 @@ import { createLockController } from '@utils/lock-controller';
import { printIonWarning } from '@utils/logging';
import { getOverlayLabelJustify, getOverlayLabelPlacement } from '@utils/overlay-control-label';
import {
+ BACKDROP,
+ cleanupRootFocusTrapAccessibility,
createDelegateController,
createTriggerController,
- BACKDROP,
dismiss,
eventMethod,
isCancel,
prepareOverlay,
present,
+ restoreRootFocusTrapAccessibility,
safeCall,
setOverlayId,
} from '@utils/overlays';
@@ -364,10 +366,16 @@ export class Alert implements ComponentInterface, OverlayInterface {
this.triggerChanged();
/**
* If the alert was previously connected and is being reattached, the
- * ResizeObserver was disconnected. componentDidLoad only fires once per
- * instance, so re-establish the observer here on reconnect.
+ * `ResizeObserver` and the button gesture were torn down. `componentDidLoad`
+ * only fires once per instance, so re-establish both here on reconnect.
*/
this.setupButtonGroupResizeObserver();
+ this.setupButtonActiveGesture();
+
+ // Re-apply the root lock if moved without dismiss() being called
+ if (this.presented) {
+ restoreRootFocusTrapAccessibility(this.el);
+ }
}
componentWillLoad() {
@@ -386,24 +394,32 @@ export class Alert implements ComponentInterface, OverlayInterface {
this.gesture = undefined;
}
+ // Clean up aria-hidden if removed without dismiss() being called
+ if (this.presented) {
+ cleanupRootFocusTrapAccessibility();
+ }
+
this.buttonGroupResizeObserver?.disconnect();
this.buttonGroupResizeObserver = undefined;
}
- componentDidLoad() {
- /**
- * Only create gesture if:
- * 1. A gesture does not already exist
- * 2. App is running in iOS mode
- * 3. A wrapper ref exists
- */
+ /**
+ * Only create gesture if:
+ * 1. A gesture does not already exist
+ * 2. App is running in iOS mode
+ * 3. A wrapper ref exists
+ */
+ private setupButtonActiveGesture() {
if (!this.gesture && getIonMode(this) === 'ios' && this.wrapperEl) {
this.gesture = createButtonActiveGesture(this.wrapperEl, (refEl: HTMLElement) =>
refEl.classList.contains('alert-button')
);
this.gesture.enable(true);
}
+ }
+ componentDidLoad() {
+ this.setupButtonActiveGesture();
this.setupButtonGroupResizeObserver();
/**
@@ -634,13 +650,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
}}
>
- {theme === 'ionic' ? (
-
- ) : (
-
- )}
+
{renderOptionLabel(optionLabelOptions, 'alert-checkbox-label')}
diff --git a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-ios-ltr-Mobile-Chrome-linux.png
index f67d7697e94..9f777bfbe8e 100644
Binary files a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-md-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-md-ltr-Mobile-Chrome-linux.png
index 63cfb58a6d3..fea53fe3d0a 100644
Binary files a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-scale-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-text-wrap-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-text-wrap-ios-ltr-Mobile-Chrome-linux.png
index 0e4c7296e26..702aac68103 100644
Binary files a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-text-wrap-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-checkbox-text-wrap-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-ios-ltr-Mobile-Chrome-linux.png
index 5345dedf71f..2af165c1e6a 100644
Binary files a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-md-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-md-ltr-Mobile-Chrome-linux.png
index 1dff67d6512..4d9419a3bd5 100644
Binary files a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-scale-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-text-wrap-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-text-wrap-ios-ltr-Mobile-Chrome-linux.png
index 39e52cb8c99..cc17202dcde 100644
Binary files a/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-text-wrap-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/a11y/alert.e2e.ts-snapshots/alert-radio-text-wrap-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts b/core/src/components/alert/test/basic/alert.e2e.ts
index aaaf5d8795c..c5b8e8a0bf2 100644
--- a/core/src/components/alert/test/basic/alert.e2e.ts
+++ b/core/src/components/alert/test/basic/alert.e2e.ts
@@ -1,7 +1,7 @@
import { expect } from '@playwright/test';
import type { Locator } from '@playwright/test';
import type { E2EPage } from '@utils/test/playwright';
-import { configs, test } from '@utils/test/playwright';
+import { configs, detachAndReattach, test } from '@utils/test/playwright';
configs({ directions: ['ltr'] }).forEach(({ config, screenshot, title }) => {
test.describe(title('alert: basic'), () => {
@@ -203,3 +203,56 @@ class AlertFixture {
await expect(this.alert).toHaveScreenshot(screenshotFn(`alert-${modifier}`));
}
}
+
+/**
+ * The button gesture only exists in iOS mode, so these run there.
+ */
+configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ config, title }) => {
+ test.describe(title('alert: moved while presented'), () => {
+ test.beforeEach(async ({ page }) => {
+ await page.goto('/src/components/alert/test/basic', config);
+ });
+
+ test('should keep the app root locked', async ({ page }, testInfo) => {
+ testInfo.annotations.push({
+ type: 'issue',
+ description: 'https://github.com/ionic-team/ionic-framework/issues/31389',
+ });
+
+ const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent');
+
+ await page.click('#basic');
+ await ionAlertDidPresent.next();
+
+ await expect(page.locator('body')).toHaveClass(/backdrop-no-scroll/);
+
+ await detachAndReattach(page.locator('ion-alert'));
+
+ await expect(page.locator('body')).toHaveClass(/backdrop-no-scroll/);
+ });
+
+ test('should keep activating buttons on press', async ({ page }, testInfo) => {
+ testInfo.annotations.push({
+ type: 'issue',
+ description: 'https://github.com/ionic-team/ionic-framework/issues/31389',
+ });
+
+ const ionAlertDidPresent = await page.spyOnEvent('ionAlertDidPresent');
+
+ await page.click('#multipleButtons');
+ await ionAlertDidPresent.next();
+
+ await detachAndReattach(page.locator('ion-alert'));
+
+ const button = page.locator('ion-alert .alert-button').first();
+ const box = (await button.boundingBox())!;
+
+ await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
+ await page.mouse.down();
+
+ await expect(button).toHaveClass(/ion-activated/);
+
+ await page.mouse.up();
+ });
+ });
+});
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Chrome-linux.png
index eb0ddcd44ac..4289a09a52f 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Firefox-linux.png
index fba30a47814..acfeb9cd115 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Safari-linux.png
index 0552d7f78ab..9cdbc33f199 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Chrome-linux.png
index e0591d9cdce..461fffc912f 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 48a4d937e42..6e5116aedfc 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Safari-linux.png
index 8d504f2f5af..e95a6405891 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-checkbox-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-ltr-Mobile-Chrome-linux.png
index 5909d31177b..422dc78df14 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-ltr-dark-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-ltr-dark-Mobile-Chrome-linux.png
index 3a25efb2319..ace7921fe82 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-ltr-dark-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-ltr-dark-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-rtl-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-rtl-Mobile-Chrome-linux.png
index 28906d81ae7..c1f3aa6076c 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-rtl-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-rtl-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-rtl-dark-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-rtl-dark-Mobile-Chrome-linux.png
index c1a9f818693..0ca5b035758 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-rtl-dark-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-ios-rtl-dark-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-Mobile-Chrome-linux.png
index 57f6cbfed1b..e8c4b4d1989 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-dark-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-dark-Mobile-Chrome-linux.png
index 7c7fad2aba5..5521188a4d2 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-dark-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-ltr-dark-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-Mobile-Chrome-linux.png
index ffa93bf0a91..ea61ad62798 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-dark-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-dark-Mobile-Chrome-linux.png
index b78b1518281..05671bfa723 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-dark-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-multipleButtons-md-rtl-dark-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 0dacb4c80a3..d6d0c1ea4a5 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 4435e9c206d..dd8944facf9 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Safari-linux.png
index 864a98ffb37..ad65d14b1c9 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Chrome-linux.png
index 12553b4d0c4..b0da637c0c7 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 7db84437ba9..881457e1a14 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Safari-linux.png
index f7430bec836..3c91c66a190 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 304ed004bc1..3ca1ad31ad6 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 11ca3ab9dcf..f4cd1aa1ab4 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Safari-linux.png
index 1eea1dbdd70..0440163c936 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Chrome-linux.png
index 7f576886d5d..fea2660a138 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 66ecb0edcd6..6476ff37b76 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Safari-linux.png
index 5a22abe44c1..07715972e0a 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-radio-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png
index ff4032624aa..48c93dbaddc 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 6d98a103218..759b7a8ff00 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png
index 09b80f4b7a4..1c0cb7ace02 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png
index 5d65998b1bc..43935863683 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 0c3c07293da..5d5cc6f46b0 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png
index 7d841325900..ad282643c49 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 120637b0f06..0d08af40faa 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png
index b90621b55b6..d9355aef38c 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png
index 7ac597bc74d..24e0ab8f2aa 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png
index a90629e7520..9f0df2cda45 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png
index cd54ccd37ff..c15db3085e7 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png
index 938bfa8c1ca..9c6e24a0f20 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-checkbox-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png
index b75949a796e..6b3f3058886 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png
index cfc1e707187..96e4666ce93 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png
index 55c4ec76397..d4bc7ed5cce 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png
index 3eb19f74d41..566b3bdf8cb 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png
index b11cf2266ce..93622eae538 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png
index 9e6424482c2..abf370ae8d5 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png
index e57bb1440f7..e10208f5f81 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png
index b54afc2ac58..46da3887567 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png
index 9062a700352..bf91f8f2cba 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png
index 6c4f66ba196..38b78589cfb 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 2aba8fd3495..cc193dbc25d 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png
index 7466d6586c6..a009da5b06d 100644
Binary files a/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/label-placement/alert.e2e.ts-snapshots/alert-label-radio-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Chrome-linux.png
index b763d66d316..93b140ba2e8 100644
Binary files a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Firefox-linux.png
index c54902e71d5..d96abfbb465 100644
Binary files a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Safari-linux.png
index f973ba46292..8870a22bfcc 100644
Binary files a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-checkbox-states-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Chrome-linux.png
index dcf60daefcf..54533bd0a61 100644
Binary files a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 28eaee45375..537d1c596aa 100644
Binary files a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Safari-linux.png
index c39055546e1..9556fa78155 100644
Binary files a/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/alert/test/states/alert.e2e.ts-snapshots/alert-radio-states-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts b/core/src/components/app/test/safe-area/app.e2e.ts
index 8778a0ecb7a..784ae125414 100644
--- a/core/src/components/app/test/safe-area/app.e2e.ts
+++ b/core/src/components/app/test/safe-area/app.e2e.ts
@@ -37,9 +37,6 @@ configs({ directions: ['ltr'], modes: ['ios', 'md', 'ionic-md'] }).forEach(({ co
test('should not have visual regressions with menu', async ({ page }) => {
await testOverlay(page, '#show-menu', 'ionDidOpen', 'menu');
});
- test('should not have visual regressions with picker', async ({ page }) => {
- await testOverlay(page, '#show-picker', 'ionPickerDidPresent', 'picker');
- });
test('should not have visual regressions with toast', async ({ page }) => {
await testOverlay(page, '#show-toast', 'ionToastDidPresent', 'toast');
});
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 09c93ab3ca7..149e331ac3e 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png
index ae012f8623d..8a7e7627c4f 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Safari-linux.png
index aea4148d201..872b381e73e 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Chrome-linux.png
index 236e564c681..fd0723f0b10 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Firefox-linux.png
index d6978bd6ab2..836fa89e6ee 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Safari-linux.png
index b1e8b7e164f..26c0a73e29c 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-ios-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Chrome-linux.png
index aa1b98b4ae0..d814abde139 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Firefox-linux.png
index fcf49ecb77d..1740e83d055 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Safari-linux.png
index 8c321b2eb7f..1f3878e99af 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-action-sheet-diff-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 7e375ecb515..1716e46dfb2 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 432c8f0b269..2adf16c32cc 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Safari-linux.png
index fd4877e17f3..8ebb205c207 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Chrome-linux.png
index 2925d01cc40..27cfb472784 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Firefox-linux.png
index 625d61957f4..fb99cd5c8a8 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Safari-linux.png
index 4c52df37741..9c810db363e 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-ios-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Chrome-linux.png
index ea931ec8fd1..e8ad96dc261 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Firefox-linux.png
index 02908f4aeb5..cd66f657693 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Safari-linux.png
index 6b4c5855199..a4e8c22c496 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-menu-diff-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Chrome-linux.png
deleted file mode 100644
index 23e78ac278d..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Chrome-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Firefox-linux.png
deleted file mode 100644
index 6796d9a484f..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Firefox-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Safari-linux.png
deleted file mode 100644
index 82f95faa291..00000000000
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-picker-diff-ios-ltr-Mobile-Safari-linux.png and /dev/null differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png
index a9eb52d18e9..e414c31d990 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 07d81c3d0bb..479f6c105a8 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Safari-linux.png
index fabe9ef03ae..5e0cb46653b 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Chrome-linux.png
index 67e9728bdc4..287ecf3e58d 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Firefox-linux.png
index 6d49226ac1d..3547ba868e2 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Safari-linux.png
index 28cf5b612cd..c04d8fdfee2 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-ios-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Chrome-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Chrome-linux.png
index 083cea5b3f8..1bd5cf03827 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Firefox-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Firefox-linux.png
index d95fc4b3aab..9c585f8d9f6 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Safari-linux.png b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Safari-linux.png
index a7684bbf153..c16e3f0513c 100644
Binary files a/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Safari-linux.png and b/core/src/components/app/test/safe-area/app.e2e.ts-snapshots/app-toast-diff-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/app/test/safe-area/index.html b/core/src/components/app/test/safe-area/index.html
index 4ad7e6beed4..6c2974100fb 100644
--- a/core/src/components/app/test/safe-area/index.html
+++ b/core/src/components/app/test/safe-area/index.html
@@ -55,7 +55,6 @@
-
@@ -115,26 +114,6 @@
await menu.open();
}
- async function showPicker() {
- const picker = Object.assign(document.createElement('ion-picker-legacy'), {
- columns: [
- {
- name: 'Picker',
- selectedIndex: 2,
- options: [
- { text: 'First' },
- { text: 'Second' },
- { text: 'Third' },
- { text: 'Fourth' },
- { text: 'Fifth' },
- ],
- },
- ],
- });
- document.body.appendChild(picker);
- await picker.present();
- }
-
async function showToast() {
const toast = Object.assign(document.createElement('ion-toast'), {
message: 'Hello world!',
diff --git a/core/src/components/avatar/avatar.ionic.scss b/core/src/components/avatar/avatar.ionic.scss
index d31e6c9c5cb..f48804c7feb 100644
--- a/core/src/components/avatar/avatar.ionic.scss
+++ b/core/src/components/avatar/avatar.ionic.scss
@@ -96,40 +96,40 @@
:host(.avatar-xxsmall.avatar-soft),
:host(.avatar-xsmall.avatar-soft),
:host(.avatar-small.avatar-soft) {
- --border-radius: #{globals.$ion-soft-2xs};
+ --border-radius: #{globals.$ion-shape-soft-2xs};
}
:host(.avatar-medium.avatar-soft) {
- --border-radius: #{globals.$ion-soft-xs};
+ --border-radius: #{globals.$ion-shape-soft-xs};
}
:host(.avatar-large.avatar-soft),
:host(.avatar-xlarge.avatar-soft) {
- --border-radius: #{globals.$ion-soft-md};
+ --border-radius: #{globals.$ion-shape-soft-md};
}
:host(.avatar-xxsmall.avatar-round),
:host(.avatar-xsmall.avatar-round),
:host(.avatar-small.avatar-round) {
- --border-radius: #{globals.$ion-round-2xs};
+ --border-radius: #{globals.$ion-shape-round-2xs};
}
:host(.avatar-medium.avatar-round) {
- --border-radius: #{globals.$ion-round-xs};
+ --border-radius: #{globals.$ion-shape-round-xs};
}
:host(.avatar-large.avatar-round),
:host(.avatar-xlarge.avatar-round) {
- --border-radius: #{globals.$ion-round-md};
+ --border-radius: #{globals.$ion-shape-round-md};
}
:host(.avatar-xxsmall.avatar-rectangular),
:host(.avatar-xsmall.avatar-rectangular),
:host(.avatar-small.avatar-rectangular) {
- --border-radius: #{globals.$ion-rectangular-2xs};
+ --border-radius: #{globals.$ion-shape-rectangular-2xs};
}
:host(.avatar-medium.avatar-rectangular) {
- --border-radius: #{globals.$ion-rectangular-xs};
+ --border-radius: #{globals.$ion-shape-rectangular-xs};
}
:host(.avatar-large.avatar-rectangular),
:host(.avatar-xlarge.avatar-rectangular) {
- --border-radius: #{globals.$ion-rectangular-md};
+ --border-radius: #{globals.$ion-shape-rectangular-md};
}
// Avatar Icon
@@ -140,33 +140,27 @@
}
:host(.avatar-xxsmall) ::slotted(ion-icon) {
- width: globals.$ion-scale-300;
- height: globals.$ion-scale-300;
+ font-size: globals.$ion-font-size-300;
}
:host(.avatar-xsmall) ::slotted(ion-icon) {
- width: globals.$ion-scale-400;
- height: globals.$ion-scale-400;
+ font-size: globals.$ion-font-size-400;
}
:host(.avatar-small) ::slotted(ion-icon) {
- width: globals.$ion-scale-500;
- height: globals.$ion-scale-500;
+ font-size: globals.$ion-font-size-500;
}
:host(.avatar-medium) ::slotted(ion-icon) {
- width: globals.$ion-scale-600;
- height: globals.$ion-scale-600;
+ font-size: globals.$ion-font-size-600;
}
:host(.avatar-large) ::slotted(ion-icon) {
- width: globals.$ion-scale-700;
- height: globals.$ion-scale-700;
+ font-size: globals.$ion-font-size-700;
}
:host(.avatar-xlarge) ::slotted(ion-icon) {
- width: globals.$ion-scale-800;
- height: globals.$ion-scale-800;
+ font-size: globals.$ion-font-size-800;
}
// Avatar Disabled
diff --git a/core/src/components/back-button/back-button.tsx b/core/src/components/back-button/back-button.tsx
index cecaf32ebd3..6cf47751dbe 100644
--- a/core/src/components/back-button/back-button.tsx
+++ b/core/src/components/back-button/back-button.tsx
@@ -1,4 +1,3 @@
-import caretLeftRegular from '@phosphor-icons/core/assets/regular/caret-left.svg';
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, h } from '@stencil/core';
import type { ButtonInterface } from '@utils/element-interface';
@@ -80,24 +79,22 @@ export class BackButton implements ComponentInterface, ButtonInterface {
}
}
- get backButtonIcon() {
+ /**
+ * Get the icon to use for the back button icon.
+ * If an icon is set on the component, use that.
+ * Otherwise, use the icon set in the config.
+ * If no icon is set in the config, use the default icon.
+ */
+ get backButtonIcon(): string {
// Return the icon if it is explicitly set
if (this.icon != null) {
return this.icon;
}
- // Determine the theme and map to default icons
+ // Determine the theme and map to the default icon
const theme = getIonTheme(this);
- const defaultIcons = {
- ios: chevronBack,
- ionic: caretLeftRegular,
- md: arrowBackSharp,
- };
-
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
+ const defaultIcon = theme === 'ios' ? chevronBack : arrowBackSharp;
- // Return the configured back button icon or the default icon
return config.get('backButtonIcon', defaultIcon);
}
@@ -106,8 +103,8 @@ export class BackButton implements ComponentInterface, ButtonInterface {
return this.text != null ? this.text : config.get('backButtonText', defaultBackButtonText);
}
- get hasIconOnly() {
- return this.backButtonIcon && !this.backButtonText;
+ get hasIconOnly(): boolean {
+ return !!this.backButtonIcon && !this.backButtonText;
}
get rippleType() {
diff --git a/core/src/components/badge/badge.interfaces.ts b/core/src/components/badge/badge.interfaces.ts
index 7e8faeacbe5..8f7104a25f4 100644
--- a/core/src/components/badge/badge.interfaces.ts
+++ b/core/src/components/badge/badge.interfaces.ts
@@ -68,8 +68,9 @@ type IonBadgeSizeContentDefinition = IonBadgeSizeDefinition & {
};
icon?: {
- width?: string;
- height?: string;
+ font?: {
+ size?: string;
+ };
};
};
diff --git a/core/src/components/badge/badge.scss b/core/src/components/badge/badge.scss
index e98d65740cf..ed12662a900 100644
--- a/core/src/components/badge/badge.scss
+++ b/core/src/components/badge/badge.scss
@@ -38,8 +38,7 @@
* @prop --ion-badge-size-small-content-font-size: Font size of the `small` size when badge has content
* @prop --ion-badge-size-small-content-font-weight: Font weight of the `small` size when badge has content
* @prop --ion-badge-size-small-content-line-height: Line height of the `small` size when badge has content
- * @prop --ion-badge-size-small-content-icon-width: Width of the slotted `ion-icon` of the `small` size
- * @prop --ion-badge-size-small-content-icon-height: Height of the slotted `ion-icon` of the `small` size
+ * @prop --ion-badge-size-small-content-icon-font-size: Size of the slotted `ion-icon` of the `small` size
* @prop --ion-badge-size-medium-content-height: Height of the `medium` size when badge has content
* @prop --ion-badge-size-medium-content-min-height: Minimum height of the `medium` size when badge has content
* @prop --ion-badge-size-medium-content-min-width: Minimum width of the `medium` size when badge has content
@@ -51,8 +50,7 @@
* @prop --ion-badge-size-medium-content-font-size: Font size of the `medium` size when badge has content
* @prop --ion-badge-size-medium-content-font-weight: Font weight of the `medium` size when badge has content
* @prop --ion-badge-size-medium-content-line-height: Line height of the `medium` size when badge has content
- * @prop --ion-badge-size-medium-content-icon-width: Width of the slotted `ion-icon` of the `medium` size
- * @prop --ion-badge-size-medium-content-icon-height: Height of the slotted `ion-icon` of the `medium` size
+ * @prop --ion-badge-size-medium-content-icon-font-size: Size of the slotted `ion-icon` of the `medium` size
* @prop --ion-badge-size-large-content-height: Height of the `large` size when badge has content
* @prop --ion-badge-size-large-content-min-height: Minimum height of the `large` size when badge has content
* @prop --ion-badge-size-large-content-min-width: Minimum width of the `large` size when badge has content
@@ -64,8 +62,7 @@
* @prop --ion-badge-size-large-content-font-size: Font size of the `large` size when badge has content
* @prop --ion-badge-size-large-content-font-weight: Font weight of the `large` size when badge has content
* @prop --ion-badge-size-large-content-line-height: Line height of the `large` size when badge has content
- * @prop --ion-badge-size-large-content-icon-width: Width of the slotted `ion-icon` of the `large` size
- * @prop --ion-badge-size-large-content-icon-height: Height of the slotted `ion-icon` of the `large` size
+ * @prop --ion-badge-size-large-content-icon-font-size: Size of the slotted `ion-icon` of the `large` size
*
* Sizes: Dot (empty with no text or icon)
* @prop --ion-badge-size-small-dot-height: Height of the `small` size when badge is empty
@@ -177,8 +174,7 @@
}
:host(.badge-size-small) ::slotted(ion-icon) {
- width: var(--ion-badge-size-small-content-icon-width, revert-layer);
- height: var(--ion-badge-size-small-content-icon-height, revert-layer);
+ font-size: var(--ion-badge-size-small-content-icon-font-size, revert-layer);
}
// Medium
@@ -202,8 +198,7 @@
}
:host(.badge-size-medium) ::slotted(ion-icon) {
- width: var(--ion-badge-size-medium-content-icon-width, revert-layer);
- height: var(--ion-badge-size-medium-content-icon-height, revert-layer);
+ font-size: var(--ion-badge-size-medium-content-icon-font-size, revert-layer);
}
// Large
@@ -227,8 +222,7 @@
}
:host(.badge-size-large) ::slotted(ion-icon) {
- width: var(--ion-badge-size-large-content-icon-width, revert-layer);
- height: var(--ion-badge-size-large-content-icon-height, revert-layer);
+ font-size: var(--ion-badge-size-large-content-icon-font-size, revert-layer);
}
// Badge Sizes: Dot (empty with no text or icon)
diff --git a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Chrome-linux.png
index c7ad180ad38..0731765aada 100644
Binary files a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Firefox-linux.png
index be8195ffb01..e72eabdece8 100644
Binary files a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Safari-linux.png
index 79a34ceff4b..5ac8b632ab0 100644
Binary files a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-bottom-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Chrome-linux.png
index af6eb12ebd2..1eaa141d43c 100644
Binary files a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Firefox-linux.png
index f64a184abc8..5ad082d3360 100644
Binary files a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Safari-linux.png
index f6974e2c586..6a10c9f973e 100644
Binary files a/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/badge/test/hint/badge.e2e.ts-snapshots/badge-hint-tab-button-icon-top-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/badge/test/hue/badge.e2e.ts-snapshots/badge-hue-bold-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/badge/test/hue/badge.e2e.ts-snapshots/badge-hue-bold-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 72bf4df8c3d..42836116f80 100644
Binary files a/core/src/components/badge/test/hue/badge.e2e.ts-snapshots/badge-hue-bold-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/badge/test/hue/badge.e2e.ts-snapshots/badge-hue-bold-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/badge/test/hue/badge.e2e.ts-snapshots/badge-hue-bold-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/badge/test/hue/badge.e2e.ts-snapshots/badge-hue-bold-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 3c93c35bb6e..d1dfc6941d0 100644
Binary files a/core/src/components/badge/test/hue/badge.e2e.ts-snapshots/badge-hue-bold-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/badge/test/hue/badge.e2e.ts-snapshots/badge-hue-bold-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/breadcrumb/breadcrumb.tsx b/core/src/components/breadcrumb/breadcrumb.tsx
index 561645e6587..d34a3840486 100644
--- a/core/src/components/breadcrumb/breadcrumb.tsx
+++ b/core/src/components/breadcrumb/breadcrumb.tsx
@@ -1,5 +1,3 @@
-import caretRightRegular from '@phosphor-icons/core/assets/regular/caret-right.svg';
-import dotsThreeRegular from '@phosphor-icons/core/assets/regular/dots-three.svg';
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Prop, h } from '@stencil/core';
import type { Attributes } from '@utils/helpers';
@@ -135,36 +133,22 @@ export class Breadcrumb implements ComponentInterface {
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
- get breadcrumbCollapsedIcon() {
- // Determine the theme and map to default icons
- const theme = getIonTheme(this);
- const defaultIcons = {
- ios: ellipsisHorizontal,
- ionic: dotsThreeRegular,
- md: ellipsisHorizontal,
- };
-
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
-
- // Return the configured breadcrumb collapsed icon or the default icon
- return config.get('breadcrumbCollapsedIcon', defaultIcon);
+ /**
+ * Get the icon to use for the collapsed icon.
+ * Use the icon set in the config.
+ * If no icon is set in the config, use the default icon.
+ */
+ get breadcrumbCollapsedIcon(): string {
+ return config.get('breadcrumbCollapsedIcon', ellipsisHorizontal);
}
- get breadcrumbSeparatorIcon() {
- // Determine the theme and map to default icons
- const theme = getIonTheme(this);
- const defaultIcons = {
- ios: chevronForwardOutline,
- ionic: caretRightRegular,
- md: chevronForwardOutline,
- };
-
- // Get the default icon based on the theme, falling back to 'md' icon if necessary
- const defaultIcon = defaultIcons[theme] || defaultIcons.md;
-
- // Return the configured breadcrumb separator icon or the default icon
- return config.get('breadcrumbSeparatorIcon', defaultIcon);
+ /**
+ * Get the icon to use for the separator icon.
+ * Use the icon set in the config.
+ * If no icon is set in the config, use the default icon.
+ */
+ get breadcrumbSeparatorIcon(): string {
+ return config.get('breadcrumbSeparatorIcon', chevronForwardOutline);
}
private isClickable(): boolean {
diff --git a/core/src/components/button/button.ionic.scss b/core/src/components/button/button.ionic.scss
index 22344274858..c1bf4e83728 100644
--- a/core/src/components/button/button.ionic.scss
+++ b/core/src/components/button/button.ionic.scss
@@ -57,7 +57,7 @@
:host(.button-outline) {
--border-width: #{globals.$ion-border-size-025};
- --border-style: #{globals.$ion-border-style-solid};
+ --border-style: solid;
--background-activated: #{globals.ion-color(primary, shade, $subtle: true)};
--background-focused: transparent;
--background-hover: #{globals.ion-color(primary, shade, $subtle: true)};
@@ -148,8 +148,7 @@
::slotted(ion-icon[slot="start"]),
::slotted(ion-icon[slot="end"]),
::slotted(ion-icon[slot="icon-only"]) {
- width: globals.$ion-scale-500;
- height: globals.$ion-scale-500;
+ font-size: globals.$ion-font-size-500;
}
}
@@ -157,8 +156,7 @@
::slotted(ion-icon[slot="start"]),
::slotted(ion-icon[slot="end"]),
::slotted(ion-icon[slot="icon-only"]) {
- width: globals.$ion-scale-600;
- height: globals.$ion-scale-600;
+ font-size: globals.$ion-font-size-600;
}
}
@@ -187,21 +185,21 @@
// --------------------------------------------------
:host(.button-soft) {
- --border-radius: #{globals.$ion-soft-xs};
+ --border-radius: #{globals.$ion-shape-soft-xs};
}
// Round Button
// --------------------------------------------------
:host(.button-round) {
- --border-radius: #{globals.$ion-round-xs};
+ --border-radius: #{globals.$ion-shape-round-xs};
}
// Rectangular Button
// --------------------------------------------------
:host(.button-rectangular) {
- --border-radius: #{globals.$ion-rectangular-xs};
+ --border-radius: #{globals.$ion-shape-rectangular-xs};
}
// Button: Focus
@@ -209,7 +207,7 @@
// Only show the focus ring when the button is focused
:host(.ion-focused) .button-native {
- outline: var(--focus-ring-width) globals.$ion-border-style-solid var(--focus-ring-color);
+ outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: globals.$ion-border-size-050;
}
diff --git a/core/src/components/button/button.tsx b/core/src/components/button/button.tsx
index 939ad04545c..7b584e205b4 100644
--- a/core/src/components/button/button.tsx
+++ b/core/src/components/button/button.tsx
@@ -1,9 +1,10 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Prop, Watch, State, forceUpdate, h } from '@stencil/core';
+import type { AttributeController } from '@utils/attribute-controller';
+import { createAriaAttributeController } from '@utils/attribute-controller';
import { createBadgeManager } from '@utils/badge-position';
import type { AnchorInterface, ButtonInterface } from '@utils/element-interface';
-import type { Attributes } from '@utils/helpers';
-import { inheritAriaAttributes, hasShadowDom, openURL } from '@utils/helpers';
+import { hasShadowDom, openURL } from '@utils/helpers';
import { printIonWarning } from '@utils/logging';
import { createColorClasses, hostContext } from '@utils/theme';
@@ -39,7 +40,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
private inButtons = false;
private formButtonEl: HTMLButtonElement | null = null;
private formEl: HTMLFormElement | null = null;
- private inheritedAttributes: Attributes = {};
+ private ariaController?: AttributeController;
@Element() el!: HTMLElement;
@@ -172,27 +173,6 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
*/
@Event() ionBlur!: EventEmitter;
- /**
- * This component is used within the `ion-input-password-toggle` component
- * to toggle the visibility of the password input.
- * These attributes need to update based on the state of the password input.
- * Otherwise, the values will be stale.
- *
- * @param newValue
- * @param _oldValue
- * @param propName
- */
- @Watch('aria-checked')
- @Watch('aria-label')
- @Watch('aria-pressed')
- onAriaChanged(newValue: string, _oldValue: string, propName: string) {
- this.inheritedAttributes = {
- ...this.inheritedAttributes,
- [propName]: newValue,
- };
- forceUpdate(this);
- }
-
/**
* This is responsible for rendering a hidden native
* button element inside the associated form. This allows
@@ -209,9 +189,13 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
/**
* If the form already has a rendered form button
- * then do not append a new one again.
+ * then do not append a new one again. Sync the
+ * disabled state and type if it changes after button
+ * creation (e.g., runtime property updates).
*/
if (formButtonEl !== null && formEl.contains(formButtonEl)) {
+ formButtonEl.disabled = this.disabled;
+ formButtonEl.type = this.type;
return;
}
@@ -231,10 +215,21 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
this.inButtons = hostContext('ion-buttons', this.el);
this.inListHeader = hostContext('ion-list-header', this.el);
this.inItem = hostContext('ion-item', this.el) || hostContext('ion-item-divider', this.el);
- this.inheritedAttributes = inheritAriaAttributes(this.el);
+
+ /**
+ * The ARIA state has to stay live, since `ion-input-password-toggle` rewrites
+ * `aria-label` and `aria-pressed` on its `ion-button` on every toggle. We keep
+ * `aria-disabled` out of the watch because the `` below renders it from the
+ * `disabled` prop and those writes would clobber a developer's value, and `role` out
+ * because a post-load write stays on the host too, which would put the same role on
+ * two elements in the accessibility tree.
+ */
+ this.ariaController = createAriaAttributeController(this.el, () => forceUpdate(this), ['aria-disabled', 'role']);
}
connectedCallback() {
+ this.ariaController?.init();
+
if (this.hasLoaded) {
this.badgeManager.init();
}
@@ -246,6 +241,7 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
}
disconnectedCallback() {
+ this.ariaController?.destroy();
this.badgeManager.destroy();
}
@@ -402,25 +398,13 @@ export class Button implements ComponentInterface, AnchorInterface, ButtonInterf
};
render() {
- const {
- buttonType,
- type,
- disabled,
- rel,
- target,
- href,
- color,
- expand,
- hasIconOnly,
- hasBadge,
- strong,
- inheritedAttributes,
- } = this;
+ const { buttonType, type, disabled, rel, target, href, color, expand, hasIconOnly, hasBadge, strong } = this;
const theme = getIonTheme(this);
const mode = getIonMode(this);
const size = this.getSize();
const shape = this.getShape();
+ const inheritedAttributes = this.ariaController?.attributes ?? {};
const TagType = href === undefined ? 'button' : ('a' as any);
const attrs =
TagType === 'button'
diff --git a/core/src/components/button/test/a11y/button.e2e.ts b/core/src/components/button/test/a11y/button.e2e.ts
index 585c0b5853d..03cf866534c 100644
--- a/core/src/components/button/test/a11y/button.e2e.ts
+++ b/core/src/components/button/test/a11y/button.e2e.ts
@@ -148,3 +148,176 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
});
});
});
+
+/**
+ * Attribute syncing does not vary across modes or directions
+ */
+configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
+ test.describe(title('button: aria attribute sync'), () => {
+ /**
+ * A sample rather than the full ARIA list, since they all go through the same
+ * membership check and looping every one of them only multiplies the run time.
+ */
+ const ariaAttributes = ['aria-checked', 'aria-label', 'aria-pressed', 'aria-description'];
+
+ for (const attr of ariaAttributes) {
+ test(`should sync ${attr} to the native button when it changes on the host`, async ({ page }) => {
+ test.info().annotations.push({
+ type: 'issue',
+ description: 'https://github.com/ionic-team/ionic-framework/issues/30626',
+ });
+
+ await page.setContent(`Button`, config);
+
+ const host = page.locator('ion-button');
+ const nativeButton = host.locator('button');
+
+ await expect(nativeButton).toHaveAttribute(attr, 'initial');
+
+ await host.evaluate((el, attr) => el.setAttribute(attr, 'updated'), attr);
+
+ await expect(nativeButton).toHaveAttribute(attr, 'updated');
+ });
+ }
+
+ test('should not sync aria-disabled from the host', async ({ page }) => {
+ await page.setContent(`Button`, config);
+
+ const host = page.locator('ion-button');
+ const nativeButton = host.locator('button');
+
+ // The developer-provided value is still copied to the native button at load.
+ await expect(nativeButton).toHaveAttribute('aria-disabled', 'true');
+
+ // The host's `aria-disabled` belongs to the `disabled` prop from here on, so later
+ // writes to it must not reach the native button. We write `aria-label` in the same
+ // batch as a barrier, since once that lands the sync has run.
+ await host.evaluate((el) => {
+ el.setAttribute('aria-disabled', 'false');
+ el.setAttribute('aria-label', 'barrier');
+ });
+ await expect(nativeButton).toHaveAttribute('aria-label', 'barrier');
+ await expect(nativeButton).toHaveAttribute('aria-disabled', 'true');
+
+ // Toggling disabled makes the component write and then clear aria-disabled on the
+ // host. Neither write should reach the native button.
+ await host.evaluate((el: HTMLIonButtonElement) => {
+ el.disabled = true;
+ el.setAttribute('aria-label', 'disabled');
+ });
+ await expect(nativeButton).toHaveAttribute('aria-label', 'disabled');
+ await expect(nativeButton).toHaveAttribute('aria-disabled', 'true');
+
+ await host.evaluate((el: HTMLIonButtonElement) => {
+ el.disabled = false;
+ el.setAttribute('aria-label', 'enabled');
+ });
+ await expect(nativeButton).toHaveAttribute('aria-label', 'enabled');
+ await expect(nativeButton).toHaveAttribute('aria-disabled', 'true');
+ });
+
+ test('should not sync role from the host', async ({ page }) => {
+ await page.setContent(`Button`, config);
+
+ const host = page.locator('ion-button');
+ const nativeButton = host.locator('button');
+
+ // The initial copy moves role onto the native button, as it always has.
+ await expect(nativeButton).toHaveAttribute('role', 'switch');
+
+ // A later write is only read, so it stays on the host. Copying it as well would put
+ // the same role on both elements, and two of that role in the accessibility tree.
+ await host.evaluate((el) => {
+ el.setAttribute('role', 'checkbox');
+ el.setAttribute('aria-label', 'barrier');
+ });
+ await expect(nativeButton).toHaveAttribute('aria-label', 'barrier');
+ await expect(nativeButton).toHaveAttribute('role', 'switch');
+ });
+
+ test('should keep syncing after the button is detached and reattached', async ({ page }) => {
+ await page.setContent(
+ `
+
+ Button
+
+ `,
+ config
+ );
+
+ const host = page.locator('ion-button');
+ const nativeButton = host.locator('button');
+
+ await expect(nativeButton).toHaveAttribute('aria-description', 'described');
+
+ await host.evaluate((el) => {
+ const parent = el.parentElement!;
+ parent.removeChild(el);
+ parent.appendChild(el);
+ });
+ await page.waitForChanges();
+
+ // The value captured at load survives the move.
+ await expect(nativeButton).toHaveAttribute('aria-description', 'described');
+
+ // Updates made after the move must still reach the native button.
+ await host.evaluate((el) => el.setAttribute('aria-description', 'updated'));
+ await expect(nativeButton).toHaveAttribute('aria-description', 'updated');
+
+ // So must one made while it was detached, when nothing is watching.
+ await host.evaluate((el) => {
+ const parent = el.parentElement!;
+ parent.removeChild(el);
+ el.setAttribute('aria-description', 'while detached');
+ parent.appendChild(el);
+ });
+ await expect(nativeButton).toHaveAttribute('aria-description', 'while detached');
+ });
+
+ test('should sync updates, empty values and removals after the initial copy', async ({ page }) => {
+ await page.setContent(`Button`, config);
+
+ const host = page.locator('ion-button');
+ const nativeButton = host.locator('button');
+
+ // The initial copy moves the value from the host to the native button.
+ await expect(host).not.toHaveAttribute('aria-description');
+ await expect(nativeButton).toHaveAttribute('aria-description', 'initial');
+
+ // Post-load writes stay on the host and are copied to the native button.
+ await host.evaluate((el) => el.setAttribute('aria-description', 'second'));
+ await expect(host).toHaveAttribute('aria-description', 'second');
+ await expect(nativeButton).toHaveAttribute('aria-description', 'second');
+
+ // An empty string is a valid ARIA attribute value.
+ await host.evaluate((el) => el.setAttribute('aria-description', ''));
+ await expect(nativeButton).toHaveAttribute('aria-description', '');
+
+ // A removal of a post-load write does reach the native button.
+ await host.evaluate((el) => el.removeAttribute('aria-description'));
+ await expect(host).not.toHaveAttribute('aria-description');
+ await expect(nativeButton).not.toHaveAttribute('aria-description');
+ });
+
+ test('should keep a value from the initial markup when the host attribute is removed', async ({ page }) => {
+ await page.setContent(`Button`, config);
+
+ const host = page.locator('ion-button');
+ const nativeButton = host.locator('button');
+
+ await expect(nativeButton).toHaveAttribute('aria-label', 'initial');
+
+ // The initial copy already took the attribute off the host, so removing it there
+ // changes nothing and the native button keeps the copied value. Setting an empty
+ // value is how you clear one of these.
+ await host.evaluate((el) => el.removeAttribute('aria-label'));
+
+ // Force a render and wait for it, otherwise the assertion passes on a button that
+ // never re-rendered at all.
+ await host.evaluate((el: HTMLIonButtonElement) => (el.color = 'primary'));
+ await expect(host).toHaveClass(/ion-color-primary/);
+
+ await expect(nativeButton).toHaveAttribute('aria-label', 'initial');
+ });
+ });
+});
diff --git a/core/src/components/button/test/badge/button.e2e.ts-snapshots/button-medium-badge-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/badge/button.e2e.ts-snapshots/button-medium-badge-ionic-md-ltr-light-Mobile-Firefox-linux.png
index f0631000e2d..b2a8615fdf9 100644
Binary files a/core/src/components/button/test/badge/button.e2e.ts-snapshots/button-medium-badge-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/badge/button.e2e.ts-snapshots/button-medium-badge-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/badge/button.e2e.ts-snapshots/button-medium-badge-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/button/test/badge/button.e2e.ts-snapshots/button-medium-badge-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 886c2bbdf07..36f5e57342b 100644
Binary files a/core/src/components/button/test/badge/button.e2e.ts-snapshots/button-medium-badge-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/badge/button.e2e.ts-snapshots/button-medium-badge-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Chrome-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Chrome-linux.png
index e5f98af9799..df773696293 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Firefox-linux.png
index 9abd073f1b1..68f2e11a232 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Safari-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Safari-linux.png
index 1fe9a0f7698..e00682fb565 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Safari-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Chrome-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Chrome-linux.png
index aa282ef1f29..7cab253c54b 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Firefox-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Firefox-linux.png
index e1605d2030a..9cac6bf875a 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Safari-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Safari-linux.png
index 9ace84c3f44..b2d9eee6015 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Safari-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-ios-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png
index b961689c797..07262ff309f 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 8bce5f752d9..4a0dad1991a 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Safari-linux.png
index 0609b9d5535..23f464b6c7e 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Chrome-linux.png
index 47f36df7b20..134047d8269 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 29214fd5066..ed163249f08 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Safari-linux.png
index b5dfadc8c6d..8fed50d7aeb 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-diff-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-ripple-effect-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-ripple-effect-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 00fa5b80c9e..69f69cf0cc1 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-ripple-effect-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-ripple-effect-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-ripple-effect-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-ripple-effect-ionic-md-rtl-light-Mobile-Firefox-linux.png
index d5a82b93b4e..982fd3816e0 100644
Binary files a/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-ripple-effect-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/basic/button.e2e.ts-snapshots/button-ripple-effect-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Chrome-linux.png b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Chrome-linux.png
index 474e9f25aff..865007ba34a 100644
Binary files a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Firefox-linux.png
index f73629c671f..e8db36736c3 100644
Binary files a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Safari-linux.png b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Safari-linux.png
index efa1910e394..bb81857fe44 100644
Binary files a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Safari-linux.png and b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-ios-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 3111ab1aaf6..600a586c7af 100644
Binary files a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 83670ae7573..302112f5409 100644
Binary files a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Safari-linux.png
index 927e09c9e3d..4c4d56f87b4 100644
Binary files a/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/button/test/clear/button.e2e.ts-snapshots/button-fill-clear-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/form-reference/button.e2e.ts b/core/src/components/button/test/form-reference/button.e2e.ts
index 5710f52da67..c85cd20760d 100644
--- a/core/src/components/button/test/form-reference/button.e2e.ts
+++ b/core/src/components/button/test/form-reference/button.e2e.ts
@@ -153,6 +153,41 @@ configs({ directions: ['ltr'], modes: ['ios'] }).forEach(({ title, config }) =>
expect(submitEvent).toHaveReceivedEvent();
});
+
+ test('should keep hidden button type in sync with visible button', async ({ page }) => {
+ // Set the form to have a submit button
+ await page.setContent(
+ `
+
+
+ Submit
+
+ `,
+ config
+ );
+
+ // Get visible button
+ const button = page.locator('ion-button');
+
+ // Get type of the hidden button
+ const getHiddenType = () =>
+ page.evaluate(() => {
+ const hidden = document.querySelector('form button[style*="display: none"]') as HTMLButtonElement;
+
+ return hidden?.type;
+ });
+
+ // Type of hidden button should be submit to start
+ expect(await getHiddenType()).toBe('submit');
+
+ // Set type of visible button to reset
+ await button.evaluate((el: HTMLIonButtonElement) => {
+ el.type = 'reset';
+ });
+
+ // Expect hidden button type to be reset
+ await expect.poll(async () => await getHiddenType()).toBe('reset');
+ });
});
test.describe(title('should throw a warning if the form cannot be found'), () => {
diff --git a/core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-ltr-Mobile-Chrome-linux.png
index 738d37bb3a4..dd33abba24d 100644
Binary files a/core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-rtl-Mobile-Chrome-linux.png b/core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-rtl-Mobile-Chrome-linux.png
index fb38d7bd1f3..4e47e7bd996 100644
Binary files a/core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-rtl-Mobile-Chrome-linux.png and b/core/src/components/button/test/icon/button.e2e.ts-snapshots/button-icon-ios-rtl-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Chrome-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Chrome-linux.png
index 6de7571155d..1cadc8d3346 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Firefox-linux.png
index c75b62c256a..9603b5c33db 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Safari-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Safari-linux.png
index 6821b153e95..203cf018f65 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Safari-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Chrome-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Chrome-linux.png
index be97b0f6159..b2888bed2ce 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Firefox-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Firefox-linux.png
index 143e0c1012e..78981500985 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Safari-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Safari-linux.png
index 5891fc6657a..0e4c366099d 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Safari-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-ios-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Chrome-linux.png
index 3987ecfc4e2..5660e0aec3f 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 0204ed72f80..1f2250c0064 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Safari-linux.png
index 9aac2bcbdd7..5195f222eb2 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Chrome-linux.png
index 8012ecaa988..9eb1b7ba0a3 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Firefox-linux.png
index 24149cd17ee..f55fd101359 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Safari-linux.png
index f9d57b15544..fa9abd66d9a 100644
Binary files a/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/button/test/outline/button.e2e.ts-snapshots/button-outline-ionic-md-rtl-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 2c67cc6cae3..44585bd3ba4 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png
index bff9b9c1712..313e466f9cb 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 93b77dd3ba3..97184f8bf99 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-rectangular-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 5235c41446a..b0f35700c9a 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 05e7d3c3deb..cfc99646b44 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 867d9166db5..e82afbd8e29 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-round-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 3ee7f0a39f5..ea3a6e683d0 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-clear-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png
index ade09aa1fe0..ef3f30c4dfc 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-default-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 4624a04161b..abc3adc8327 100644
Binary files a/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/shape/button.e2e.ts-snapshots/button-shape-soft-fill-outline-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/button/test/spinner/button.e2e.ts-snapshots/button-spinner-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/button/test/spinner/button.e2e.ts-snapshots/button-spinner-ionic-md-ltr-light-Mobile-Firefox-linux.png
index f4f13087ddb..98d675f34ac 100644
Binary files a/core/src/components/button/test/spinner/button.e2e.ts-snapshots/button-spinner-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/button/test/spinner/button.e2e.ts-snapshots/button-spinner-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/buttons/buttons.ionic.scss b/core/src/components/buttons/buttons.ionic.scss
index e4df0bb0d37..31f7e76cc4f 100644
--- a/core/src/components/buttons/buttons.ionic.scss
+++ b/core/src/components/buttons/buttons.ionic.scss
@@ -29,5 +29,5 @@
}
::slotted(*) ion-icon[slot="icon-only"] {
- font-size: globals.$ion-font-size-600;
+ font-size: globals.$ion-font-size-500;
}
diff --git a/core/src/components/card/card.ionic.scss b/core/src/components/card/card.ionic.scss
index b55aeee1551..40d6a2c4115 100755
--- a/core/src/components/card/card.ionic.scss
+++ b/core/src/components/card/card.ionic.scss
@@ -8,8 +8,8 @@
--background: #{globals.$ion-bg-surface-default};
--border-width: #{globals.$ion-border-size-025};
--border-color: #{globals.$ion-border-default};
- --border-style: #{globals.$ion-border-style-solid};
- --border-radius: #{globals.$ion-round-xl};
+ --border-style: solid;
+ --border-radius: #{globals.$ion-shape-round-xl};
--color: #{globals.$ion-text-default};
min-width: globals.$ion-scale-2400;
@@ -24,13 +24,13 @@
// ---------------------------------------------
:host(.card-soft) {
- --border-radius: #{globals.$ion-soft-xl};
+ --border-radius: #{globals.$ion-shape-soft-xl};
}
:host(.card-round) {
- --border-radius: #{globals.$ion-round-xl};
+ --border-radius: #{globals.$ion-shape-round-xl};
}
:host(.card-rectangular) {
- --border-radius: #{globals.$ion-rectangular-xl};
+ --border-radius: #{globals.$ion-shape-rectangular-xl};
}
diff --git a/core/src/components/card/card.tsx b/core/src/components/card/card.tsx
index 746ac85d999..c37c0fd4fa8 100644
--- a/core/src/components/card/card.tsx
+++ b/core/src/components/card/card.tsx
@@ -1,8 +1,9 @@
import type { ComponentInterface } from '@stencil/core';
-import { Element, Component, Host, Prop, h } from '@stencil/core';
+import { Element, Component, Host, Prop, h, forceUpdate } from '@stencil/core';
+import type { AttributeController } from '@utils/attribute-controller';
+import { createAttributeController } from '@utils/attribute-controller';
import type { AnchorInterface, ButtonInterface } from '@utils/element-interface';
-import type { Attributes } from '@utils/helpers';
-import { inheritAttributes, openURL } from '@utils/helpers';
+import { openURL } from '@utils/helpers';
import { createColorClasses } from '@utils/theme';
import { getIonTheme } from '../../global/ionic-global';
@@ -25,7 +26,7 @@ import type { RouterDirection } from '../router/utils/interface';
shadow: true,
})
export class Card implements ComponentInterface, AnchorInterface, ButtonInterface {
- private inheritedAriaAttributes: Attributes = {};
+ private ariaController?: AttributeController;
@Element() el!: HTMLElement;
/**
@@ -97,7 +98,20 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
@Prop() target: string | undefined;
componentWillLoad() {
- this.inheritedAriaAttributes = inheritAttributes(this.el, ['aria-label']);
+ /**
+ * Only the initial copy takes the attribute off the host, so an `aria-label` written
+ * after load stays on the host too. That's harmless here, because unlike `ion-item`
+ * the card host renders no role of its own, so nothing reads the leftover copy.
+ */
+ this.ariaController = createAttributeController(this.el, ['aria-label'], () => forceUpdate(this));
+ }
+
+ connectedCallback() {
+ this.ariaController?.init();
+ }
+
+ disconnectedCallback() {
+ this.ariaController?.destroy();
}
private isClickable(): boolean {
@@ -110,7 +124,8 @@ export class Card implements ComponentInterface, AnchorInterface, ButtonInterfac
if (!clickable) {
return [];
}
- const { href, routerAnimation, routerDirection, inheritedAriaAttributes } = this;
+ const { href, routerAnimation, routerDirection } = this;
+ const inheritedAriaAttributes = this.ariaController?.attributes ?? {};
const TagType = clickable ? (href === undefined ? 'button' : 'a') : ('div' as any);
const attrs =
TagType === 'button'
diff --git a/core/src/components/card/test/a11y/card.e2e.ts b/core/src/components/card/test/a11y/card.e2e.ts
index 6902037f998..7adb42ed5e7 100644
--- a/core/src/components/card/test/a11y/card.e2e.ts
+++ b/core/src/components/card/test/a11y/card.e2e.ts
@@ -32,3 +32,130 @@ configs({ directions: ['ltr'] }).forEach(({ title, screenshot, config }) => {
});
});
});
+
+/**
+ * Attribute syncing does not vary across modes or directions
+ */
+configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
+ test.describe(title('card: aria attribute sync'), () => {
+ test('should sync aria-label to the native element when it changes on the host', async ({ page }) => {
+ test.info().annotations.push({
+ type: 'issue',
+ description: 'https://github.com/ionic-team/ionic-framework/issues/30626',
+ });
+
+ await page.setContent(`Card`, config);
+
+ const host = page.locator('ion-card');
+ const nativeCard = host.locator('[part="native"]');
+
+ await expect(nativeCard).toHaveAttribute('aria-label', 'label');
+
+ await host.evaluate((el) => el.setAttribute('aria-label', 'updated'));
+
+ await expect(nativeCard).toHaveAttribute('aria-label', 'updated');
+ });
+
+ test('should keep syncing after the card is detached and reattached', async ({ page }) => {
+ await page.setContent(
+ `
+
+ Card
+
+ `,
+ config
+ );
+
+ const host = page.locator('ion-card');
+ const nativeCard = host.locator('[part="native"]');
+
+ await expect(nativeCard).toHaveAttribute('aria-label', 'label');
+
+ await host.evaluate((el) => {
+ const parent = el.parentElement!;
+ parent.removeChild(el);
+ parent.appendChild(el);
+ });
+ await page.waitForChanges();
+
+ // The value captured at load survives the move.
+ await expect(nativeCard).toHaveAttribute('aria-label', 'label');
+
+ // Updates made after the move must still reach the native element.
+ await host.evaluate((el) => el.setAttribute('aria-label', 'updated'));
+ await expect(nativeCard).toHaveAttribute('aria-label', 'updated');
+
+ // So must one made while it was detached, when nothing is watching.
+ await host.evaluate((el) => {
+ const parent = el.parentElement!;
+ parent.removeChild(el);
+ el.setAttribute('aria-label', 'while detached');
+ parent.appendChild(el);
+ });
+ await expect(nativeCard).toHaveAttribute('aria-label', 'while detached');
+ });
+
+ test('should sync updates, empty values and removals after the initial copy', async ({ page }) => {
+ await page.setContent(`Card`, config);
+
+ const host = page.locator('ion-card');
+ const nativeCard = host.locator('[part="native"]');
+
+ // The initial copy moves the value from the host to the native element.
+ await expect(host).not.toHaveAttribute('aria-label');
+ await expect(nativeCard).toHaveAttribute('aria-label', 'initial');
+
+ // Post-load writes stay on the host and are copied to the native element.
+ await host.evaluate((el) => el.setAttribute('aria-label', 'second'));
+ await expect(host).toHaveAttribute('aria-label', 'second');
+ await expect(nativeCard).toHaveAttribute('aria-label', 'second');
+
+ // An empty string is a valid ARIA attribute value.
+ await host.evaluate((el) => el.setAttribute('aria-label', ''));
+ await expect(nativeCard).toHaveAttribute('aria-label', '');
+
+ // A removal of a post-load write does reach the native element.
+ await host.evaluate((el) => el.removeAttribute('aria-label'));
+ await expect(host).not.toHaveAttribute('aria-label');
+ await expect(nativeCard).not.toHaveAttribute('aria-label');
+ });
+
+ test('should apply aria-label to the native element when the card becomes clickable', async ({ page }) => {
+ await page.setContent(`Card`, config);
+
+ const host = page.locator('ion-card');
+ await page.waitForChanges();
+
+ // A card that is neither a button nor a link renders no native element.
+ await expect(host.locator('[part="native"]')).toHaveCount(0);
+
+ // Both `button` and `href` can be set after load, and the native element that
+ // appears then still needs the label copied at load.
+ await host.evaluate((el: HTMLIonCardElement) => (el.button = true));
+
+ await expect(host.locator('[part="native"]')).toHaveAttribute('aria-label', 'label');
+ });
+
+ test('should not sync ARIA attributes other than aria-label', async ({ page }) => {
+ await page.setContent(`Card`, config);
+
+ const host = page.locator('ion-card');
+ const nativeCard = host.locator('[part="native"]');
+
+ /**
+ * Only `aria-label` should reach the native element. A wider watch set would put
+ * attributes there after load that the element never gets at load.
+ */
+ await host.evaluate((el) => {
+ el.setAttribute('role', 'presentation');
+ el.setAttribute('aria-describedby', 'hint');
+ // Written in the same batch as a barrier, since once it lands the sync has run.
+ el.setAttribute('aria-label', 'updated');
+ });
+
+ await expect(nativeCard).toHaveAttribute('aria-label', 'updated');
+ await expect(nativeCard).not.toHaveAttribute('aria-describedby');
+ await expect(nativeCard).not.toHaveAttribute('role');
+ });
+ });
+});
diff --git a/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png
index f237e7885c9..8985228e23c 100644
Binary files a/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png
index 3367531f71d..6106c6ca8cb 100644
Binary files a/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Safari-linux.png
index eb061e8dae2..fedbdb7a491 100644
Binary files a/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/card/test/shape/card.e2e.ts-snapshots/card-soft-ionic-md-ltr-light-Mobile-Safari-linux.png differ
diff --git a/core/src/components/checkbox/checkbox.common.scss b/core/src/components/checkbox/checkbox.common.scss
index 20d86101e78..34649132295 100644
--- a/core/src/components/checkbox/checkbox.common.scss
+++ b/core/src/components/checkbox/checkbox.common.scss
@@ -7,6 +7,7 @@
/**
* @prop --size: Size of the checkbox icon
*
+ * @prop --checkbox-background: Background of the checkbox icon
* @prop --checkbox-background-checked: Background of the checkbox icon when checked
*
* @prop --border-color: Border color of the checkbox icon
@@ -18,7 +19,7 @@
* @prop --transition: Transition of the checkbox icon
*
* @prop --checkmark-color: Color of the checkbox checkmark when checked
- * @prop --checkmark-width: Stroke width of the checkbox checkmark
+ * @prop --checkmark-width: Stroke width of the checkbox checkmark. Only applies when no icon is set in the config.
*/
display: inline-block;
@@ -53,7 +54,7 @@
width: auto;
}
-// Hide the native focus outline.
+// Hide the native focus ring since we draw our own focus indicator.
:host(:focus) {
outline: none;
}
@@ -97,17 +98,52 @@ input {
}
.native-wrapper {
+ @include mixins.border-radius(var(--border-radius));
+
display: flex;
+ position: relative;
+
+ flex-shrink: 0;
+
align-items: center;
+
+ width: var(--size);
+ height: var(--size);
+
+ transition: var(--transition);
+
+ border-width: var(--border-width);
+ border-style: var(--border-style);
+ border-color: var(--border-color);
+
+ background: var(--checkbox-background);
+
+ box-sizing: border-box;
}
+// Checkbox Icon
+// ----------------------------------------------------------------
+
+/**
+ * Apply the color to the ion-icon container so that the default
+ * checkmark icon and any configured icon apply color consistently.
+ */
.checkbox-icon {
- position: relative;
+ color: var(--checkmark-color);
+
+ opacity: 0;
+}
+
+.checkbox-icon svg {
+ width: 100%;
+ height: 100%;
}
.checkbox-icon path {
- opacity: 0;
+ fill: none;
+ stroke: currentColor;
+ stroke-width: var(--checkmark-width);
}
// Checkbox Bottom Content
@@ -247,15 +283,15 @@ input {
// Checked / Indeterminate Checkbox
// ---------------------------------------------
-:host(.checkbox-checked) .checkbox-icon,
-:host(.checkbox-indeterminate) .checkbox-icon {
+:host(.checkbox-checked) .native-wrapper,
+:host(.checkbox-indeterminate) .native-wrapper {
border-color: var(--border-color-checked);
background: var(--checkbox-background-checked);
}
-:host(.checkbox-checked) .checkbox-icon path,
-:host(.checkbox-indeterminate) .checkbox-icon path {
+:host(.checkbox-checked) .checkbox-icon,
+:host(.checkbox-indeterminate) .checkbox-icon {
opacity: 1;
}
diff --git a/core/src/components/checkbox/checkbox.ionic.scss b/core/src/components/checkbox/checkbox.ionic.scss
index d4d298b896d..8922f3c02df 100644
--- a/core/src/components/checkbox/checkbox.ionic.scss
+++ b/core/src/components/checkbox/checkbox.ionic.scss
@@ -6,8 +6,6 @@
:host {
/**
- * @prop --checkmark-height: Stroke height of the checkbox checkmark
- *
* @prop --focus-ring-color: Color of the focus ring
* @prop --focus-ring-width: Width of the focus ring
* @prop --focus-ring-offset: Offset of the focus ring
@@ -15,10 +13,9 @@
// Border
--border-width: #{globals.$ion-border-size-025};
- --border-style: #{globals.$ion-border-style-solid};
+ --border-style: solid;
--border-color: #{globals.$ion-primitives-neutral-800};
- --checkmark-width: #{globals.$ion-scale-400};
- --checkmark-height: var(--checkmark-width);
+ --checkmark-width: 3;
// Focus
--focus-ring-color: #{globals.$ion-border-focus-default};
@@ -53,10 +50,6 @@
z-index: 1;
}
-
- .native-wrapper {
- position: relative;
- }
}
.label-text-wrapper {
@@ -80,33 +73,16 @@ input {
}
.native-wrapper {
- @include globals.border-radius(var(--border-radius));
-
- flex-shrink: 0;
-
justify-content: center;
-
- width: var(--size);
- height: var(--size);
-
- transition: var(--transition);
-
- border-width: var(--border-width);
- border-style: var(--border-style);
- border-color: var(--border-color);
-
- background: var(--checkbox-background);
-
- box-sizing: border-box;
}
-.checkbox-icon {
- width: var(--checkmark-width);
- height: var(--checkmark-height);
-}
+// Checkbox Icon
+// ----------------------------------------------------------------
-.checkbox-icon path {
- fill: var(--checkmark-color);
+// The mark is inset within the container, so it is
+// sized as a share of the container.
+.checkbox-icon {
+ font-size: calc(var(--size) * 2 / 3);
}
// Checkbox Hint Text
@@ -186,15 +162,6 @@ input {
--size: #{globals.$ion-scale-400};
}
-// Checked / Indeterminate Checkbox
-// ---------------------------------------------
-:host(.checkbox-checked) .native-wrapper,
-:host(.checkbox-indeterminate) .native-wrapper {
- border-color: var(--border-color-checked);
-
- background: var(--checkbox-background-checked);
-}
-
// Ionic Design Checkbox Invalid
// --------------------------------------------------
:host(.ion-invalid) {
@@ -236,9 +203,7 @@ input {
}
:host(:hover.checkbox-checked) .native-wrapper,
- :host(:hover.checkbox-checked) .checkbox-icon,
- :host(:hover.checkbox-indeterminate) .native-wrapper,
- :host(:hover.checkbox-indeterminate) .checkbox-icon {
+ :host(:hover.checkbox-indeterminate) .native-wrapper {
background-color: globals.$ion-semantics-primary-800;
}
}
@@ -247,7 +212,7 @@ input {
// --------------------------------------------------
// Only show the focus ring when the checkbox is focused and not disabled
:host(.ion-focused:not(.checkbox-disabled)) .native-wrapper {
- @include globals.focused-state(var(--focus-ring-width), globals.$ion-border-style-solid, var(--focus-ring-color));
+ @include globals.focused-state(var(--focus-ring-width), solid, var(--focus-ring-color));
}
// Checkbox: Active
@@ -257,9 +222,7 @@ input {
}
:host(.ion-activated.checkbox-checked) .native-wrapper,
-:host(.ion-activated.checkbox-checked) .checkbox-icon,
-:host(.ion-activated.checkbox-indeterminate) .native-wrapper,
-:host(.ion-activated.checkbox-indeterminate) .checkbox-icon {
+:host(.ion-activated.checkbox-indeterminate) .native-wrapper {
background-color: globals.$ion-bg-primary-base-press;
}
diff --git a/core/src/components/checkbox/checkbox.md.scss b/core/src/components/checkbox/checkbox.md.scss
index 80a28a5e91c..fe6c7b2ebba 100644
--- a/core/src/components/checkbox/checkbox.md.scss
+++ b/core/src/components/checkbox/checkbox.md.scss
@@ -22,6 +22,9 @@
--size: #{$checkbox-md-icon-size};
}
+// Checkbox Icon
+// --------------------------------------------------------
+
.checkbox-icon path {
stroke-dasharray: 30;
stroke-dashoffset: 30;
diff --git a/core/src/components/checkbox/checkbox.native.scss b/core/src/components/checkbox/checkbox.native.scss
index 4c9021f114f..e5e44fb36c3 100644
--- a/core/src/components/checkbox/checkbox.native.scss
+++ b/core/src/components/checkbox/checkbox.native.scss
@@ -6,9 +6,6 @@
// --------------------------------------------------
:host {
- /**
- * @prop --checkbox-background: Background of the checkbox icon
- */
--checkbox-background-checked: #{ion-color(primary, base)};
--border-color-checked: #{ion-color(primary, base)};
--checkmark-color: #{ion-color(primary, contrast)};
@@ -23,6 +20,32 @@
--checkmark-color: #{current-color(contrast)};
}
+// Checkbox: Keyboard Focus
+// ---------------------------------------------
+
+:host(.ion-focused) .native-wrapper::after {
+ @include border-radius(50%);
+
+ display: block;
+ position: absolute;
+
+ width: $checkbox-focus-ring-size;
+ height: $checkbox-focus-ring-size;
+
+ background: $checkbox-background-color-focused;
+
+ content: "";
+ opacity: 0.2;
+
+ // The indicator overhangs the control, so it must not take pointer events;
+ // otherwise it widens the hit area and swallows clicks aimed past the control.
+ pointer-events: none;
+
+ // Centered with insets because `transform` is physical and breaks in RTL.
+ inset-block-start: calc(50% - #{$checkbox-focus-ring-size} / 2);
+ inset-inline-start: calc(50% - #{$checkbox-focus-ring-size} / 2);
+}
+
// Checkboxes that are not slotted inside an item and are not used with a
// stacked label should have margins equal to those of the label.
:host(.in-item) .label-text-wrapper,
@@ -38,27 +61,12 @@
@include margin(null, null, $checkbox-item-label-margin-bottom, null);
}
-.checkbox-icon {
- @include border-radius(var(--border-radius));
-
- width: var(--size);
- height: var(--size);
-
- transition: var(--transition);
-
- border-width: var(--border-width);
- border-style: var(--border-style);
- border-color: var(--border-color);
-
- background: var(--checkbox-background);
-
- box-sizing: border-box;
-}
+// Checkbox Icon
+// ----------------------------------------------------------------
-.checkbox-icon path {
- fill: none;
- stroke: var(--checkmark-color);
- stroke-width: var(--checkmark-width);
+.checkbox-icon {
+ width: 100%;
+ height: 100%;
}
// Checkbox Bottom Content
diff --git a/core/src/components/checkbox/checkbox.tsx b/core/src/components/checkbox/checkbox.tsx
index 2a26468fa1c..6d0906d9e22 100644
--- a/core/src/components/checkbox/checkbox.tsx
+++ b/core/src/components/checkbox/checkbox.tsx
@@ -1,10 +1,11 @@
import type { ComponentInterface, EventEmitter } from '@stencil/core';
-import { Build, Component, Element, Event, Host, Method, Prop, State, h } from '@stencil/core';
-import { checkInvalidState } from '@utils/forms';
+import { Build, Component, Element, Event, Host, Method, Prop, State, forceUpdate, h } from '@stencil/core';
+import { checkInvalidState, createItemMultipleInputsObserver } from '@utils/forms';
import type { Attributes } from '@utils/helpers';
import { inheritAriaAttributes, renderHiddenInput } from '@utils/helpers';
import { createColorClasses, hostContext } from '@utils/theme';
+import { config } from '../../global/config';
import { getIonTheme } from '../../global/ionic-global';
import type { Color, Theme } from '../../interface';
@@ -18,7 +19,8 @@ import type { CheckboxChangeEventDetail } from './checkbox-interface';
*
* @part container - The container for the checkbox mark.
* @part label - The label text describing the checkbox.
- * @part mark - The checkmark used to indicate the checked state.
+ * @part icon - The icon that displays the checked or indeterminate mark.
+ * @part mark - The mark used to indicate the checked or indeterminate state. Only applies when no icon is set in the config.
* @part supporting-text - Supporting text displayed beneath the checkbox label.
* @part helper-text - Supporting text displayed beneath the checkbox label when the checkbox is valid.
* @part error-text - Supporting text displayed beneath the checkbox label when the checkbox is invalid and touched.
@@ -39,6 +41,7 @@ export class Checkbox implements ComponentInterface {
private errorTextId = `${this.inputId}-error-text`;
private inheritedAttributes: Attributes = {};
private validationObserver?: MutationObserver;
+ private itemFocusObserver?: MutationObserver;
@Element() el!: HTMLIonCheckboxElement;
@@ -212,6 +215,8 @@ export class Checkbox implements ComponentInterface {
// Always set initial state
this.isInvalid = checkInvalidState(el);
this.hasLabelContent = this.el.textContent !== '';
+
+ this.itemFocusObserver = createItemMultipleInputsObserver(el, () => forceUpdate(this));
}
componentWillLoad() {
@@ -223,11 +228,14 @@ export class Checkbox implements ComponentInterface {
}
disconnectedCallback() {
- // Clean up validation observer to prevent memory leaks.
if (this.validationObserver) {
this.validationObserver.disconnect();
this.validationObserver = undefined;
}
+ if (this.itemFocusObserver) {
+ this.itemFocusObserver.disconnect();
+ this.itemFocusObserver = undefined;
+ }
}
/** @internal */
@@ -290,6 +298,22 @@ export class Checkbox implements ComponentInterface {
ev.stopPropagation();
};
+ /**
+ * Get the icon to use for the checked icon.
+ * Use the icon set in the config.
+ */
+ get checkboxCheckedIcon(): string | undefined {
+ return config.get('checkboxCheckedIcon');
+ }
+
+ /**
+ * Get the icon to use for the indeterminate icon.
+ * Use the icon set in the config.
+ */
+ get checkboxIndeterminateIcon(): string | undefined {
+ return config.get('checkboxIndeterminateIcon');
+ }
+
private getHintTextId(): string | undefined {
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
@@ -335,6 +359,8 @@ export class Checkbox implements ComponentInterface {
render() {
const {
color,
+ checkboxCheckedIcon,
+ checkboxIndeterminateIcon,
checked,
disabled,
el,
@@ -352,8 +378,10 @@ export class Checkbox implements ComponentInterface {
size,
} = this;
const theme = getIonTheme(this);
+ const markIcon = indeterminate ? checkboxIndeterminateIcon : checkboxCheckedIcon;
const path = getSVGPath(theme, indeterminate);
const inItem = hostContext('ion-item', el);
+ const inMultipleInputsItem = hostContext('ion-item.item-multiple-inputs', el);
renderHiddenInput(true, el, name, checked ? value : '', disabled);
@@ -379,10 +407,11 @@ export class Checkbox implements ComponentInterface {
'in-item': inItem,
'checkbox-checked': checked,
'checkbox-disabled': disabled,
- // Focus styling should not apply when the checkbox is in an item
- 'ion-focusable': !inItem,
'checkbox-indeterminate': indeterminate,
interactive: true,
+ // A single-input item has the input cover and draws the indicator itself.
+ // A multi-input item has no cover, so each control draws its own.
+ 'ion-focusable': !inItem || inMultipleInputsItem,
[`checkbox-justify-${justify}`]: justify !== undefined,
[`checkbox-alignment-${alignment}`]: alignment !== undefined,
[`checkbox-label-placement-${labelPlacement}`]: true,
@@ -416,16 +445,26 @@ export class Checkbox implements ComponentInterface {
{this.renderHintText()}
-