Skip to content

bug: ion-select with a long list of options is slow to open #31658

Open

Description

@denodell

Prerequisites

Ionic Framework Version

v9.x

Current Behavior

An ion-select with the popover interface takes much longer to open as its list of options grows, and the page is unresponsive for most of that time.

With a full ISO country list of 249 options, it took 1,266ms to open with the CPU slowed down 4x in Chrome 155, compared with 203ms for a 50 option list. The page was unresponsive for 1,133ms of that time. I found out that each new option takes longer to add than the one before it did!

Expected Behavior

Each option should take about the same time to add, so opening the select with 250 options takes at most about five times as long as with 50, and the page should stay responsive while it's opening.

Steps to Reproduce

  1. Clone the reproduction repo from https://github.com/denodell/ionic-select-slow-open-repro
  2. Run npm install, then npm start, and open the page it serves.
  3. In Chrome's developer tools, set CPU throttling to 4x in the Performance panel.
  4. Click "Use 50 options", then click the select to open it. Close it.
  5. Click "Use 250 options", then click the select to open it again.
  6. The table I put on the page shows measurements of how long each took to open, and the longest frame length while it opened. With 250 options it takes four to five times as long as with 50!

Code Reproduction URL

https://github.com/denodell/ionic-select-slow-open-repro

Ionic Info

@ionic/core 9.0.7, Chrome 155. The reproduction repo doesn't use the Ionic CLI, so there's no output from ionic info.

Additional Information

The actual reason for this happening is Stencil's replacement appendChild function, which experimentalSlotFixes enables. Because ion-radio-group doesn't use shadow DOM, each new ion-radio causes Stencil to check all the existing options in the group twice, once to find the right slot and once to work out where the new one goes. You can see this in a Performance panel recording of the select opening, where most of the time taken is in Stencil's runtime, with its replacement appendChild taking around half of the total time.

I've raised that already with the Stencil team here: stenciljs/core#6973

On Ionic's side, giving ion-radio-group shadow DOM would avoid it, since the browser would handle the slots. I realize that changes how apps can style the group, so it might need to wait for a major release.

Activity

  1. thetaPC commented on Oct 27, 2026

    @thetaPC
    Contributor

    Thanks for the report, and for the detailed measurements!

    Verified on 9.0.9. The single-select popover and modal interfaces render their options inside an ion-radio-group, which doesn't use shadow DOM, so each option goes through Stencil's slot patch for non-shadow components. That patch searches every option already in the group before adding the next one, which makes opening the select slower with every option. This also affects any ion-radio-group with a long list of radios, not only the select. One detail for your Stencil issue: in our profile, the second pass over the options is the fallback slot visibility check that runs after each insert, not the lookup of where the new option goes. Tracking the last node per slot would only remove about half of the cost.

    We plan to convert ion-radio-group to shadow DOM, which fixes this because the browser handles the slotting. Because it changes how apps can style the group, it is a breaking change and needs to ship in a major release. We'll keep this issue up to date as that work progresses.

    In the meantime, the alert interface doesn't use ion-radio-group and opens in about the same time whatever the number of options:

    <ion-select interface="alert" label="Country">
      ...
    </ion-select>

    The action-sheet interface isn't affected either, though it is less practical for a list this long.

  2. denodell commented on Oct 28, 2026

    @denodell
    Author

    Thanks for checking it so quickly, @thetaPC, and for the alert workaround!

    You're right that most of the time goes on the fallback slot visibility check, I was mistaken before. In a quick test I just ran with my CPU slowed down 4x, appending 2,000 children to a Stencil component took 19.7 seconds, 18.2 seconds with the last node per slot cached (what I thought was going to fix the issue), and 2.7 seconds with the updateFallbackSlotVisibility call removed (what you rightly pointed me to). I've added a correction to the Stencil issue.

    Converting ion-radio-group to shadow DOM sounds like a good fix. I'm happy to help test it when there's a build to try!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions