diff --git a/core/src/components/action-sheet/action-sheet.tsx b/core/src/components/action-sheet/action-sheet.tsx
index beda9b01ac0..187b7ac9096 100644
--- a/core/src/components/action-sheet/action-sheet.tsx
+++ b/core/src/components/action-sheet/action-sheet.tsx
@@ -564,7 +564,11 @@ export class ActionSheet implements ComponentInterface, OverlayInterface {
id={buttonId}
class={{
...buttonClass(b),
- 'action-sheet-selected': isActiveRadio,
+ // Only override `action-sheet-selected` when this button participates
+ // in the radio group. For non-radio buttons we let `buttonClass(b)`
+ // own the class so the public `role: 'selected'` API keeps working
+ // (regression from #30769 / issue #31090).
+ ...(isRadio && { 'action-sheet-selected': isActiveRadio }),
}}
onClick={() => {
if (isRadio) {
diff --git a/core/src/components/action-sheet/test/basic/action-sheet.spec.tsx b/core/src/components/action-sheet/test/basic/action-sheet.spec.tsx
index fce291525f2..09ae98880d4 100644
--- a/core/src/components/action-sheet/test/basic/action-sheet.spec.tsx
+++ b/core/src/components/action-sheet/test/basic/action-sheet.spec.tsx
@@ -59,3 +59,38 @@ describe('action sheet: disabled buttons', () => {
await expect(cancelButton.hasAttribute('disabled')).toBe(false);
});
});
+
+describe('action sheet: role="selected"', () => {
+ // Regression test for https://github.com/ionic-team/ionic-framework/issues/31090
+ // Buttons with `role: "selected"` must render the `action-sheet-selected`
+ // class so that userland CSS targeting the active option keeps working.
+ it('should add the action-sheet-selected class to a button with role="selected"', async () => {
+ const page = await newSpecPage({
+ components: [ActionSheet],
+ template: () => (
+
+ ),
+ });
+
+ const actionSheet = page.body.querySelector('ion-action-sheet')!;
+
+ await actionSheet.present();
+
+ const buttons = Array.from(actionSheet.querySelectorAll('.action-sheet-button'));
+ const selectedButton = buttons.find((btn) => btn.textContent?.trim() === 'Option B');
+
+ await expect(selectedButton).toBeDefined();
+ await expect(selectedButton!.classList.contains('action-sheet-selected')).toBe(true);
+
+ const optionA = buttons.find((btn) => btn.textContent?.trim() === 'Option A');
+ await expect(optionA!.classList.contains('action-sheet-selected')).toBe(false);
+ });
+});