Skip to content

bug: ion-action-sheet button with role: "selected" no longer gets action-sheet-selected class #31090

@aeharding

Description

@aeharding

Prerequisites

Ionic Framework Version

v8.x

Current Behavior

Passing role: "selected" on an ActionSheetButton no longer causes the rendered <button> to receive the action-sheet-selected CSS class. Userland styling that targets .action-sheet-selected (the documented hook for marking the active option — e.g. bold text, a custom checkmark, etc.) silently stops working.

Expected Behavior

The button with role: "selected" should render with the action-sheet-selected class, as it has since the component's introduction and as described in the ActionSheetButton docs.

Steps to Reproduce

Steps to Reproduce

Minimal, no framework, straight from the CDN:

<!doctype html>
<html>
  <head>
    <link rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@ionic/core@8.8.4/css/ionic.bundle.css">
    <script type="module"
      src="https://cdn.jsdelivr.net/npm/@ionic/core@8.8.4/dist/ionic/ionic.esm.js"></script>
  </head>
  <body>
    <button id="open">Open</button>
    <ion-action-sheet id="sheet" header="Choose"></ion-action-sheet>
    <script type="module">
      await customElements.whenDefined("ion-action-sheet");
      const sheet = document.getElementById("sheet");
      sheet.buttons = [
        { text: "Option A", data: "a" },
        { text: "Option B", data: "b", role: "selected" },
        { text: "Option C", data: "c" },
        { text: "Cancel",   role: "cancel" },
      ];
      document.getElementById("open").addEventListener("click", async () => {
        await sheet.present();
        setTimeout(() => {
          const btns = sheet.querySelectorAll("button.action-sheet-button");
          btns.forEach(b => console.log(b.textContent.trim(), "→", b.className));
        }, 200);
      });
    </script>
  </body>
</html>

Click "Open", then inspect the DOM / console output.

Actual output (8.7.12 – 8.8.4)

Option A → action-sheet-button ion-activatable ion-focusable sc-ion-action-sheet-md
Option B → action-sheet-button ion-activatable ion-focusable sc-ion-action-sheet-md
Option C → action-sheet-button ion-activatable ion-focusable sc-ion-action-sheet-md
Cancel   → action-sheet-button ion-activatable ion-focusable action-sheet-cancel sc-ion-action-sheet-md

Expected output (same HTML against 8.7.11)

Option A → action-sheet-button ion-activatable ion-focusable sc-ion-action-sheet-md
Option B → action-sheet-button ion-activatable ion-focusable action-sheet-selected sc-ion-action-sheet-md
Option C → action-sheet-button ion-activatable ion-focusable sc-ion-action-sheet-md
Cancel   → action-sheet-button ion-activatable ion-focusable action-sheet-cancel sc-ion-action-sheet-md

Code Reproduction URL

https://stackblitz.com/edit/uzl2pn3y-1fhhizgy

Ionic Info

n/a

Additional Information

Version bisection (CDN)

Version .action-sheet-selected applied?
8.6.5
8.7.0
8.7.11
8.7.12
8.8.0
8.8.4

Suspected cause

Introduced by #30769 ("select, action-sheet: use radio role for options"), shipped in 8.7.12. The new render path for action-sheet buttons wraps them in a radio group and computes action-sheet-selected from activeRadioId (which is only populated by buttons whose htmlAttributes.role === "radio" and htmlAttributes["aria-checked"]=== "true"). The legacy public role: "selected" branch was removed from the button class assignment, so the class never makes it into the DOM anymore.

Impact

This is the documented mechanism for highlighting the active option and is used widely in the wild (see Ionic's own docs and examples). The change silently breaks custom checkmark / emphasis styling in every consumer relying on the class hook.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions