From fd6066c7c4b893270ca3057d9497e02a0a6c9357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Louren=C3=A7o?= Date: Wed, 3 Dec 2025 16:37:40 +0000 Subject: [PATCH 1/8] Make radio-group use the Shadow DOM --- core/api.txt | 5 +++- .../radio-group/radio-group.common.scss | 6 ++-- .../radio-group/radio-group.ionic.scss | 28 +++++++++++-------- .../radio-group/radio-group.ios.scss | 2 +- .../radio-group/radio-group.md.scss | 2 +- .../radio-group/radio-group.native.scss | 7 ----- .../components/radio-group/radio-group.tsx | 16 ++++------- .../test/supporting-text/index.html | 4 +-- .../test/supporting-text/radio-group.e2e.ts | 8 +++--- 9 files changed, 36 insertions(+), 42 deletions(-) diff --git a/core/api.txt b/core/api.txt index e4597ef5934..ee56463070f 100644 --- a/core/api.txt +++ b/core/api.txt @@ -1845,7 +1845,7 @@ ion-radio,part,container ion-radio,part,label ion-radio,part,mark -ion-radio-group,none +ion-radio-group,shadow 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 @@ -1855,6 +1855,9 @@ ion-radio-group,prop,name,string,this.inputId,false,false ion-radio-group,prop,theme,"ios" | "md" | "ionic",undefined,false,false ion-radio-group,prop,value,any,undefined,false,false ion-radio-group,event,ionChange,RadioGroupChangeEventDetail,true +ion-radio-group,part,error-text +ion-radio-group,part,helper-text +ion-radio-group,part,top ion-range,shadow ion-range,prop,activeBarStart,number | undefined,undefined,false,false diff --git a/core/src/components/radio-group/radio-group.common.scss b/core/src/components/radio-group/radio-group.common.scss index d05b6edae77..c87c23ce45e 100644 --- a/core/src/components/radio-group/radio-group.common.scss +++ b/core/src/components/radio-group/radio-group.common.scss @@ -1,7 +1,7 @@ // Radio Group: Common // -------------------------------------------------- -ion-radio-group { +:host { // Prevents additional pixels from being rendered on top vertical-align: top; } @@ -21,10 +21,10 @@ ion-radio-group { display: block; } -.ion-touched.ion-invalid .radio-group-top .error-text { +:host(.ion-touched.ion-invalid) .radio-group-top .error-text { display: block; } -.ion-touched.ion-invalid .radio-group-top .helper-text { +:host(.ion-touched.ion-invalid) .radio-group-top .helper-text { display: none; } diff --git a/core/src/components/radio-group/radio-group.ionic.scss b/core/src/components/radio-group/radio-group.ionic.scss index 9f88be770ff..293942b4b5d 100644 --- a/core/src/components/radio-group/radio-group.ionic.scss +++ b/core/src/components/radio-group/radio-group.ionic.scss @@ -23,16 +23,20 @@ // 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 { - /* stylelint-disable */ - @include globals.ltr() { - padding-right: globals.$ion-space-400; - padding-left: calc(globals.$ion-space-400 + var(--ion-safe-area-left, 0px)); - } - - @include globals.rtl() { - padding-right: calc(globals.$ion-space-400 + var(--ion-safe-area-right, 0px)); - padding-left: globals.$ion-space-400; - } - /* stylelint-enable */ +// Note: :host-context() cannot be nested inside ltr()/rtl() mixins +// because the mixin tries to transform the selector, creating invalid CSS. +// We work around this by using separate rules outside the mixins. +/* stylelint-disable */ +:host-context(ion-list) .radio-group-top { + // Default to LTR - padding-left includes safe area + padding-right: globals.$ion-space-400; + padding-left: calc(globals.$ion-space-400 + var(--ion-safe-area-left, 0px)); } + +// RTL support - match when document or ancestor has dir="rtl" +:host-context([dir="rtl"] ion-list) .radio-group-top, +:host-context(ion-list) .radio-group-top:dir(rtl) { + padding-right: calc(globals.$ion-space-400 + var(--ion-safe-area-right, 0px)); + padding-left: globals.$ion-space-400; +} +/* stylelint-enable */ diff --git a/core/src/components/radio-group/radio-group.ios.scss b/core/src/components/radio-group/radio-group.ios.scss index 67fccf8513d..1cad5288dd4 100644 --- a/core/src/components/radio-group/radio-group.ios.scss +++ b/core/src/components/radio-group/radio-group.ios.scss @@ -7,6 +7,6 @@ // 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 { +:host-context(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 index 009a8fe58c4..aa9147cea64 100644 --- a/core/src/components/radio-group/radio-group.md.scss +++ b/core/src/components/radio-group/radio-group.md.scss @@ -7,6 +7,6 @@ // 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 { +:host-context(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.native.scss b/core/src/components/radio-group/radio-group.native.scss index c0a65bdd955..8cce2004169 100644 --- a/core/src/components/radio-group/radio-group.native.scss +++ b/core/src/components/radio-group/radio-group.native.scss @@ -1,13 +1,6 @@ @import "./radio-group.common"; @import "../../themes/native/native.globals"; -// Radio Group: Native -// -------------------------------------------------- - -.radio-group-wrapper { - display: inline; -} - // Radio Group: Top // -------------------------------------------------- diff --git a/core/src/components/radio-group/radio-group.tsx b/core/src/components/radio-group/radio-group.tsx index ae95316c25c..dacac7aeb5c 100644 --- a/core/src/components/radio-group/radio-group.tsx +++ b/core/src/components/radio-group/radio-group.tsx @@ -18,6 +18,7 @@ import type { RadioGroupChangeEventDetail, RadioGroupCompareFn } from './radio-g md: 'radio-group.md.scss', ionic: 'radio-group.ionic.scss', }, + shadow: true, }) export class RadioGroup implements ComponentInterface { private inputId = `ion-rg-${radioGroupIds++}`; @@ -317,11 +318,11 @@ export class RadioGroup implements ComponentInterface { } return ( -
-
+
+
{!isInvalid ? helperText : null}
- @@ -360,14 +361,7 @@ export class RadioGroup implements ComponentInterface { onClick={this.onClick} > {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 index 9abc0e42d68..46a4a9bd3e5 100644 --- a/core/src/components/radio-group/test/supporting-text/index.html +++ b/core/src/components/radio-group/test/supporting-text/index.html @@ -30,10 +30,10 @@ ion-radio { width: 100%; } - .custom .helper-text { + .custom::part(helper-text) { color: green; } - .custom .error-text { + .custom::part(error-text) { color: purple; } 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 index a3d12d63e20..bb772ba7286 100644 --- 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 @@ -197,11 +197,11 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co await page.setContent( ` @@ -222,11 +222,11 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co await page.setContent( ` From 36f444a209c5d5e0bedf47cf578dc16032d6a51b Mon Sep 17 00:00:00 2001 From: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:18:33 -0500 Subject: [PATCH 2/8] fix(radio-group): add display block to host to expand to children's height --- core/src/components/radio-group/radio-group.common.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/components/radio-group/radio-group.common.scss b/core/src/components/radio-group/radio-group.common.scss index c87c23ce45e..27dbae0590e 100644 --- a/core/src/components/radio-group/radio-group.common.scss +++ b/core/src/components/radio-group/radio-group.common.scss @@ -2,6 +2,8 @@ // -------------------------------------------------- :host { + display: block; + // Prevents additional pixels from being rendered on top vertical-align: top; } From 67df7370301b97437f906074f67359d8239bd398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Louren=C3=A7o?= Date: Thu, 4 Dec 2025 12:07:19 +0000 Subject: [PATCH 3/8] Apply suggestions from code review Co-authored-by: Brandy Smith --- core/src/components/radio-group/radio-group.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/components/radio-group/radio-group.tsx b/core/src/components/radio-group/radio-group.tsx index dacac7aeb5c..b7797b293a1 100644 --- a/core/src/components/radio-group/radio-group.tsx +++ b/core/src/components/radio-group/radio-group.tsx @@ -318,11 +318,11 @@ export class RadioGroup implements ComponentInterface { } return ( -
-
+
+
{!isInvalid ? helperText : null}
- From f89d756861d9d662f27f72a8a08fbc649fee2eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Louren=C3=A7o?= Date: Thu, 4 Dec 2025 13:18:19 +0000 Subject: [PATCH 4/8] CR + remove now unnecessary vertical-align --- core/api.txt | 2 +- .../radio-group/radio-group.common.scss | 3 -- .../radio-group/radio-group.ionic.scss | 28 ++++++++---------- .../radio-group/radio-group.ios.scss | 2 +- .../radio-group/radio-group.md.scss | 2 +- .../components/radio-group/radio-group.tsx | 6 ++++ .../test/supporting-text/radio-group.e2e.ts | 4 +-- ...-custom-css-md-ltr-Mobile-Safari-linux.png | Bin 5910 -> 6018 bytes ...error-text-ios-ltr-Mobile-Chrome-linux.png | Bin 2357 -> 2318 bytes ...rror-text-ios-ltr-Mobile-Firefox-linux.png | Bin 4175 -> 4204 bytes ...error-text-ios-ltr-Mobile-Safari-linux.png | Bin 3343 -> 3361 bytes ...-error-text-md-ltr-Mobile-Safari-linux.png | Bin 5630 -> 5743 bytes ...-custom-css-md-ltr-Mobile-Safari-linux.png | Bin 6396 -> 6507 bytes ...elper-text-ios-ltr-Mobile-Chrome-linux.png | Bin 2326 -> 2233 bytes ...lper-text-ios-ltr-Mobile-Firefox-linux.png | Bin 4133 -> 4163 bytes ...elper-text-ios-ltr-Mobile-Safari-linux.png | Bin 3536 -> 3556 bytes ...helper-text-md-ltr-Mobile-Safari-linux.png | Bin 5741 -> 5852 bytes 17 files changed, 23 insertions(+), 24 deletions(-) diff --git a/core/api.txt b/core/api.txt index ee56463070f..40013c461ec 100644 --- a/core/api.txt +++ b/core/api.txt @@ -1857,7 +1857,7 @@ ion-radio-group,prop,value,any,undefined,false,false ion-radio-group,event,ionChange,RadioGroupChangeEventDetail,true ion-radio-group,part,error-text ion-radio-group,part,helper-text -ion-radio-group,part,top +ion-radio-group,part,supporting-text ion-range,shadow ion-range,prop,activeBarStart,number | undefined,undefined,false,false diff --git a/core/src/components/radio-group/radio-group.common.scss b/core/src/components/radio-group/radio-group.common.scss index 27dbae0590e..d7fbb0b7ba4 100644 --- a/core/src/components/radio-group/radio-group.common.scss +++ b/core/src/components/radio-group/radio-group.common.scss @@ -3,9 +3,6 @@ :host { display: block; - - // Prevents additional pixels from being rendered on top - vertical-align: top; } // Radio Group: Top diff --git a/core/src/components/radio-group/radio-group.ionic.scss b/core/src/components/radio-group/radio-group.ionic.scss index 293942b4b5d..d8b614dfce4 100644 --- a/core/src/components/radio-group/radio-group.ionic.scss +++ b/core/src/components/radio-group/radio-group.ionic.scss @@ -23,20 +23,16 @@ // Add padding to the error and helper text when used in a // list to align them with the list header and item text. -// Note: :host-context() cannot be nested inside ltr()/rtl() mixins -// because the mixin tries to transform the selector, creating invalid CSS. -// We work around this by using separate rules outside the mixins. -/* stylelint-disable */ -:host-context(ion-list) .radio-group-top { - // Default to LTR - padding-left includes safe area - padding-right: globals.$ion-space-400; - padding-left: calc(globals.$ion-space-400 + var(--ion-safe-area-left, 0px)); +:host(.in-list) .radio-group-top { + /* stylelint-disable */ + @include globals.ltr() { + padding-right: globals.$ion-space-400; + padding-left: calc(globals.$ion-space-400 + var(--ion-safe-area-left, 0px)); + } + + @include globals.rtl() { + padding-right: calc(globals.$ion-space-400 + var(--ion-safe-area-right, 0px)); + padding-left: globals.$ion-space-400; + } + /* stylelint-enable */ } - -// RTL support - match when document or ancestor has dir="rtl" -:host-context([dir="rtl"] ion-list) .radio-group-top, -:host-context(ion-list) .radio-group-top:dir(rtl) { - padding-right: calc(globals.$ion-space-400 + var(--ion-safe-area-right, 0px)); - padding-left: globals.$ion-space-400; -} -/* stylelint-enable */ diff --git a/core/src/components/radio-group/radio-group.ios.scss b/core/src/components/radio-group/radio-group.ios.scss index 1cad5288dd4..8c42026831e 100644 --- a/core/src/components/radio-group/radio-group.ios.scss +++ b/core/src/components/radio-group/radio-group.ios.scss @@ -7,6 +7,6 @@ // Add padding to the error and helper text when used in a // list to align them with the list header and item text. -:host-context(ion-list) .radio-group-top { +:host(.in-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 index aa9147cea64..5483e27ce5c 100644 --- a/core/src/components/radio-group/radio-group.md.scss +++ b/core/src/components/radio-group/radio-group.md.scss @@ -7,6 +7,6 @@ // Add padding to the error and helper text when used in a // list to align them with the list header and item text. -:host-context(ion-list) .radio-group-top { +:host(.in-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.tsx b/core/src/components/radio-group/radio-group.tsx index b7797b293a1..3056f8692f8 100644 --- a/core/src/components/radio-group/radio-group.tsx +++ b/core/src/components/radio-group/radio-group.tsx @@ -6,10 +6,15 @@ import { renderHiddenInput } from '@utils/helpers'; import { getIonTheme } from '../../global/ionic-global'; import type { RadioGroupChangeEventDetail, RadioGroupCompareFn } from './radio-group-interface'; +import {hostContext} from "@utils/theme"; /** * @virtualProp {"ios" | "md"} mode - The mode determines the platform behaviors of the component. * @virtualProp {"ios" | "md" | "ionic"} theme - The theme determines the visual appearance of the component. + * + * @part supporting-text - Supporting text displayed above the radios. + * @part helper-text - Supporting text displayed above the radios when the radio group is valid. + * @part error-text - Supporting text displayed above the radios when the radio group is invalid and touched. */ @Component({ tag: 'ion-radio-group', @@ -353,6 +358,7 @@ export class RadioGroup implements ComponentInterface { - ion-radio-group::part(top) { + ion-radio-group::part(supporting-text) { font-size: 20px; } @@ -222,7 +222,7 @@ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, screenshot, co await page.setContent( `