diff --git a/core/api.txt b/core/api.txt index c1d2b772d7..201c86c28d 100644 --- a/core/api.txt +++ b/core/api.txt @@ -1352,6 +1352,8 @@ ion-radio,part,mark ion-radio-group,none ion-radio-group,prop,allowEmptySelection,boolean,false,false,false ion-radio-group,prop,compareWith,((currentValue: any, compareValue: any) => boolean) | null | string | undefined,undefined,false,false +ion-radio-group,prop,errorText,string | undefined,undefined,false,false +ion-radio-group,prop,helperText,string | undefined,undefined,false,false ion-radio-group,prop,name,string,this.inputId,false,false ion-radio-group,prop,value,any,undefined,false,false ion-radio-group,event,ionChange,RadioGroupChangeEventDetail,true diff --git a/core/src/components.d.ts b/core/src/components.d.ts index ac38d78837..c458b85150 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -2315,6 +2315,14 @@ export namespace Components { * This property allows developers to specify a custom function or property name for comparing objects when determining the selected option in the ion-radio-group. When not specified, the default behavior will use strict equality (===) for comparison. */ "compareWith"?: string | RadioGroupCompareFn | null; + /** + * The error text to display at the top of the radio group. + */ + "errorText"?: string; + /** + * The helper text to display at the top of the radio group. + */ + "helperText"?: string; /** * The name of the control, which is submitted with the form data. */ @@ -7111,6 +7119,14 @@ declare namespace LocalJSX { * This property allows developers to specify a custom function or property name for comparing objects when determining the selected option in the ion-radio-group. When not specified, the default behavior will use strict equality (===) for comparison. */ "compareWith"?: string | RadioGroupCompareFn | null; + /** + * The error text to display at the top of the radio group. + */ + "errorText"?: string; + /** + * The helper text to display at the top of the radio group. + */ + "helperText"?: string; /** * The name of the control, which is submitted with the form data. */ diff --git a/core/src/components/radio-group/radio-group.ios.scss b/core/src/components/radio-group/radio-group.ios.scss new file mode 100644 index 0000000000..eff6fb0ca3 --- /dev/null +++ b/core/src/components/radio-group/radio-group.ios.scss @@ -0,0 +1,12 @@ +@import "../../themes/ionic.globals.ios"; +@import "./radio-group"; +@import "../item/item.ios.vars"; + +// iOS Radio Group Top in List +// -------------------------------------------------- + +// Add padding to the error and helper text when used in a +// list to align them with the list header and item text. +ion-list .radio-group-top { + @include padding-horizontal($item-ios-padding-start, $item-ios-padding-end); +} diff --git a/core/src/components/radio-group/radio-group.md.scss b/core/src/components/radio-group/radio-group.md.scss new file mode 100644 index 0000000000..dc36adc2a2 --- /dev/null +++ b/core/src/components/radio-group/radio-group.md.scss @@ -0,0 +1,12 @@ +@import "../../themes/ionic.globals.md"; +@import "./radio-group"; +@import "../item/item.md.vars"; + +// Material Design Radio Group Top in List +// -------------------------------------------------- + +// Add padding to the error and helper text when used in a +// list to align them with the list header and item text. +ion-list .radio-group-top { + @include padding-horizontal($item-md-padding-start, $item-md-padding-end); +} diff --git a/core/src/components/radio-group/radio-group.scss b/core/src/components/radio-group/radio-group.scss new file mode 100644 index 0000000000..3eceab4405 --- /dev/null +++ b/core/src/components/radio-group/radio-group.scss @@ -0,0 +1,44 @@ +@import "../../themes/ionic.globals"; + +// Radio Group +// -------------------------------------------------- + +ion-radio-group { + // Prevents additional pixels from being rendered on top + vertical-align: top; +} + +.radio-group-wrapper { + display: inline; +} + +// Radio Group: Top +// -------------------------------------------------- + +.radio-group-top { + line-height: 1.5; +} + +/** + * Error text should only be shown when .ion-invalid is present + * on the radio group. Otherwise the helper text should be shown. + */ +.radio-group-top .error-text { + display: none; + + color: ion-color(danger, base); +} + +.radio-group-top .helper-text { + display: block; + + color: $text-color-step-300; +} + +.ion-touched.ion-invalid .radio-group-top .error-text { + display: block; +} + +.ion-touched.ion-invalid .radio-group-top .helper-text { + display: none; +} diff --git a/core/src/components/radio-group/radio-group.tsx b/core/src/components/radio-group/radio-group.tsx index a8762b5f8a..c3e1e4c0b0 100644 --- a/core/src/components/radio-group/radio-group.tsx +++ b/core/src/components/radio-group/radio-group.tsx @@ -8,9 +8,15 @@ import type { RadioGroupChangeEventDetail, RadioGroupCompareFn } from './radio-g @Component({ tag: 'ion-radio-group', + styleUrls: { + ios: 'radio-group.ios.scss', + md: 'radio-group.md.scss', + }, }) export class RadioGroup implements ComponentInterface { private inputId = `ion-rg-${radioGroupIds++}`; + private helperTextId = `${this.inputId}-helper-text`; + private errorTextId = `${this.inputId}-error-text`; private labelId = `${this.inputId}-lbl`; private label?: HTMLIonLabelElement | null; @@ -39,6 +45,16 @@ export class RadioGroup implements ComponentInterface { */ @Prop({ mutable: true }) value?: any | null; + /** + * The helper text to display at the top of the radio group. + */ + @Prop() helperText?: string; + + /** + * The error text to display at the top of the radio group. + */ + @Prop() errorText?: string; + @Watch('value') valueChanged(value: any | undefined) { this.setRadioTabindex(value); @@ -224,13 +240,69 @@ export class RadioGroup implements ComponentInterface { radioToFocus?.setFocus(); } + /** + * Renders the helper text or error text values + */ + private renderHintText() { + const { helperText, errorText, helperTextId, errorTextId } = this; + + const hasHintText = !!helperText || !!errorText; + if (!hasHintText) { + return; + } + + return ( +
+
+ {helperText} +
+
+ {errorText} +
+
+ ); + } + + private getHintTextID(): string | undefined { + const { el, helperText, errorText, helperTextId, errorTextId } = this; + + if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) { + return errorTextId; + } + + if (helperText) { + return helperTextId; + } + + return undefined; + } + render() { const { label, labelId, el, name, value } = this; const mode = getIonMode(this); renderHiddenInput(true, el, name, value, false); - return ; + return ( + + {this.renderHintText()} + {/* + TODO(FW-6279): Wrapping the slot in a div is a workaround due to a + Stencil issue. Without the wrapper, the children radio will fire the + blur event on focus, instead of waiting for them to be blurred. + */} +
+ +
+
+ ); } } diff --git a/core/src/components/radio-group/test/supporting-text/index.html b/core/src/components/radio-group/test/supporting-text/index.html new file mode 100644 index 0000000000..9abc0e42d6 --- /dev/null +++ b/core/src/components/radio-group/test/supporting-text/index.html @@ -0,0 +1,207 @@ + + + + + Radio Group - Supporting Text + + + + + + + + + + + + + + Radio Group - Supporting Text + + + + +
+
+

No Supporting Text

+ + Label + Label + Label + Label + Label + +
+ +
+

Helper Text

+ + Label + Label + Label + Label + Label + +
+ +
+

Error Text

+ + Label + Label + Label + Label + Label + +
+ +
+ + List + + + Label + + + Label + + + Label + + + Label + + + Label + + + +
+ +
+ + Supporting Text: List + + + Label + + + Label + + + Label + + + Label + + + Label + + + +
+ +
+ + Error Text: List + + + Label + + + Label + + + Label + + + Label + + + Label + + + +
+ +
+

Helper Text: Custom

+ + Label + Label + Label + Label + Label + +
+ +
+

Error Text: Custom

+ + Label + Label + Label + Label + Label + +
+
+ + + + +
+
+ + diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts new file mode 100644 index 0000000000..e33d0a3546 --- /dev/null +++ b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts @@ -0,0 +1,247 @@ +import { expect } from '@playwright/test'; +import { configs, test } from '@utils/test/playwright'; + +/** + * Functionality is the same across modes & directions + */ +configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => { + test.describe(title('radio group: supporting text functionality'), () => { + test('should not render top content if no hint is enabled', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const bottomEl = page.locator('ion-radio-group .radio-group-top'); + await expect(bottomEl).toHaveCount(0); + }); + test('helper text should be visible initially', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const helperText = page.locator('ion-radio-group .helper-text'); + const errorText = page.locator('ion-radio-group .error-text'); + await expect(helperText).toBeVisible(); + await expect(helperText).toHaveText('Helper text'); + await expect(errorText).toBeHidden(); + }); + test('radio group should have an aria-describedby attribute when helper text is present', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + const helperText = page.locator('ion-radio-group .helper-text'); + const helperTextId = await helperText.getAttribute('id'); + const ariaDescribedBy = await radioGroup.getAttribute('aria-describedby'); + + expect(ariaDescribedBy).toBe(helperTextId); + }); + test('error text should be visible when radio group is invalid', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const helperText = page.locator('ion-radio-group .helper-text'); + const errorText = page.locator('ion-radio-group .error-text'); + await expect(helperText).toBeHidden(); + await expect(errorText).toBeVisible(); + await expect(errorText).toHaveText('Error text'); + }); + + test('radio group should have an aria-describedby attribute when error text is present', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + const errorText = page.locator('ion-radio-group .error-text'); + const errorTextId = await errorText.getAttribute('id'); + const ariaDescribedBy = await radioGroup.getAttribute('aria-describedby'); + + expect(ariaDescribedBy).toBe(errorTextId); + }); + test('radio group should have aria-invalid attribute when radio group is invalid', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + + await expect(radioGroup).toHaveAttribute('aria-invalid'); + }); + test('radio group should not have aria-invalid attribute when radio group is valid', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + + await expect(radioGroup).not.toHaveAttribute('aria-invalid'); + }); + test('radio group should not have aria-describedby attribute when no hint or error text is present', async ({ + page, + }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + + await expect(radioGroup).not.toHaveAttribute('aria-describedby'); + }); + }); +}); + +/** + * Rendering is different across modes + */ +configs({ modes: ['ios', 'md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { + test.describe(title('radio-group: supporting text rendering'), () => { + test('should not have visual regressions when rendering helper text', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + await expect(radioGroup).toHaveScreenshot(screenshot(`radio-group-helper-text`)); + }); + + test('should not have visual regressions when rendering error text', async ({ page }) => { + await page.setContent( + ` + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + await expect(radioGroup).toHaveScreenshot(screenshot(`radio-group-error-text`)); + }); + }); +}); + +/** + * Customizing supporting text is the same across modes and directions + */ +configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, config }) => { + test.describe(title('radio group: supporting text customization'), () => { + test('should not have visual regressions when rendering helper text with custom css', async ({ page }) => { + await page.setContent( + ` + + + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + await expect(radioGroup).toHaveScreenshot(screenshot(`radio-group-helper-text-custom-css`)); + }); + test('should not have visual regressions when rendering error text with custom css', async ({ page }) => { + await page.setContent( + ` + + + + Label + Label + Label + + `, + config + ); + + const radioGroup = page.locator('ion-radio-group'); + await expect(radioGroup).toHaveScreenshot(screenshot(`radio-group-error-text-custom-css`)); + }); + }); +}); diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Chrome-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..5f9e7dede9 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Firefox-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..672e43129f Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Safari-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..2162ada7e6 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-custom-css-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..3d3357b320 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..6f1b840b6e Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Safari-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..34398dd3b7 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Chrome-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..5818434c54 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Firefox-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..d5b7036b8d Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Safari-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..3f9ca304d4 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-error-text-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Chrome-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..d478d59b84 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Firefox-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..83665d55e5 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Safari-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..c3c5818f6b Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-custom-css-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..0273116bf6 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..8fcd29e304 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Safari-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..9604e7e1fd Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Chrome-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..8833f7c072 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Firefox-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..0c4f44f1a2 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Safari-linux.png b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Safari-linux.png new file mode 100644 index 0000000000..bac1d69231 Binary files /dev/null and b/core/src/components/radio-group/test/supporting-text/radio-group.e2e.ts-snapshots/radio-group-helper-text-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-ios-ltr-Mobile-Chrome-linux.png index 475da30dda..74768be0ad 100644 Binary files a/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-ios-ltr-Mobile-Firefox-linux.png index fd8a84627a..6d5593aede 100644 Binary files a/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-ios-ltr-Mobile-Firefox-linux.png differ diff --git a/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-md-ltr-Mobile-Chrome-linux.png b/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-md-ltr-Mobile-Chrome-linux.png index 6240454fbe..01ba887bdc 100644 Binary files a/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-md-ltr-Mobile-Firefox-linux.png b/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-md-ltr-Mobile-Firefox-linux.png index a9c83cfa0a..6968c85969 100644 Binary files a/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/radio/test/a11y/radio.e2e.ts-snapshots/radio-scale-md-ltr-Mobile-Firefox-linux.png differ diff --git a/packages/angular/common/src/directives/control-value-accessors/value-accessor.ts b/packages/angular/common/src/directives/control-value-accessors/value-accessor.ts index 9c4dc7444b..30715544eb 100644 --- a/packages/angular/common/src/directives/control-value-accessors/value-accessor.ts +++ b/packages/angular/common/src/directives/control-value-accessors/value-accessor.ts @@ -52,6 +52,13 @@ export class ValueAccessor implements ControlValueAccessor, AfterViewInit, OnDes if (el === this.elementRef.nativeElement) { this.onTouched(); setIonicClasses(this.elementRef); + + // When ion-radio is blurred, el and this.elementRef.nativeElement are + // different so we need to check if the closest ion-radio-group is the same + // as this.elementRef.nativeElement and if so, we need to mark the radio group + // as touched + } else if (el.closest('ion-radio-group') === this.elementRef.nativeElement) { + this.onTouched(); } } diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index f638e0c3e3..cfa828e322 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -1639,14 +1639,14 @@ export declare interface IonRadio extends Components.IonRadio { @ProxyCmp({ - inputs: ['allowEmptySelection', 'compareWith', 'name', 'value'] + inputs: ['allowEmptySelection', 'compareWith', 'errorText', 'helperText', 'name', 'value'] }) @Component({ selector: 'ion-radio-group', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['allowEmptySelection', 'compareWith', 'name', 'value'], + inputs: ['allowEmptySelection', 'compareWith', 'errorText', 'helperText', 'name', 'value'], }) export class IonRadioGroup { protected el: HTMLIonRadioGroupElement; diff --git a/packages/angular/standalone/src/directives/radio-group.ts b/packages/angular/standalone/src/directives/radio-group.ts index 925f48182b..acba66c60d 100644 --- a/packages/angular/standalone/src/directives/radio-group.ts +++ b/packages/angular/standalone/src/directives/radio-group.ts @@ -16,7 +16,7 @@ import { defineCustomElement } from '@ionic/core/components/ion-radio-group.js'; import { ProxyCmp, proxyOutputs } from './angular-component-lib/utils'; -const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'compareWith', 'name', 'value']; +const RADIO_GROUP_INPUTS = ['allowEmptySelection', 'compareWith', 'errorText', 'helperText', 'name', 'value']; /** * Pulling the provider into an object and using PURE works diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index 28da8d5882..b25fd491b5 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -698,6 +698,8 @@ export const IonRadioGroup = /*@__PURE__*/ defineContainer