Skip to content

bug: In Android API 36, the safe-area is not respected. #30900

Open

Description

@Marius-Romanus

Prerequisites

Ionic Framework Version

v8.x

Current Behavior

This is due to switching to Capacitor 8, which uses Android API 36, where windowOptOutEdgeToEdgeEnforcement no longer works:

https://capacitorjs.com/docs/apis/status-bar#android-16-behavior-change

Modals and popovers (that I've seen) are not respecting the safe area.

I've implemented the SystemBars plugin with insetsHandling in CSS, but it makes no difference:

https://capacitorjs.com/docs/apis/system-bars#android-note

It seems the only place where it's respected is the top element, if you have an ion-header in CSS:

ion-header ion-toolbar:first-of-type {
    padding-top: var(--ion-safe-area-top, 0);
}

I've tested it on the following emulators:

Pixel 9 Pro - API 36
Pixel 7 Pro - API 35
Pixel 6a - API 33

Image Image

Expected Behavior

The safe area should always be respected in all cases and at all edges.

Steps to Reproduce

npm i
ionic capacitor build android

Enable "Navigation mode: Buttons" if it's set to "Gestures"
See the modal and popover in tab 1.

The global CSS contains:

html {
    --ion-safe-area-top: var(--safe-area-inset-top, env(safe-area-inset-top, 0px));
    --ion-safe-area-bottom: var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px));
    --ion-safe-area-left: var(--safe-area-inset-left, env(safe-area-inset-left, 0px));
    --ion-safe-area-right: var(--safe-area-inset-right, env(safe-area-inset-right, 0px));
}

Code Reproduction URL

https://github.com/Marius-Romanus/safe-area-ionic

Ionic Info

Ionic:
   Ionic CLI: 7.2.1
   Ionic Framework: @ionic/angular 8.7.15
   @angular-devkit/build-angular: not installed
   @angular-devkit/schematics: 20.3.13
   @angular/cli: 21.0.4
   @ionic/angular-toolkit: 12.3.0

Capacitor:
   Capacitor CLI: 8.0.0
   @capacitor/android: 8.0.0
   @capacitor/core: 8.0.0
   @capacitor/ios: not installed

Utility:
   cordova-res: not installed globally
   native-run: 2.0.1

System:
   NodeJS: v24.11.0
   npm: 11.7.0
   OS: Windows 10

Additional Information

No response

Activity

  1. ShaneK commented on Dec 31, 2025

    @ShaneK
    Member

    Hello! Thanks for your report. I actually have a PR up that addresses this here:
    #30889

    Along with a dev build, if you'd like to try it. Please report any issues you find with the dev build or that solution there. Most of our team is OOO until the 5th, so it probably won't be in a patch release until the 7th at the earliest.

  2. reopened this on Dec 31, 2025
  3. ShaneK commented on Dec 31, 2025

    @ShaneK
    Member

    This is kind of a weird situation. Normally I'd close this as a duplicate, but the duplicate it's of is internal, and this was opened after the PR to fix it. So I guess I'll just update the PR to say it resolves this and it'll be closed when merged

  4. Marius-Romanus commented on Dec 31, 2025

    @Marius-Romanus
    Author

    I tried version 8.7.16-dev.11767019759.14b7f2fa and the same thing happens.

    Most of our team is OOO until the 5th, so it probably won't be in a patch release until the 7th at the earliest.

    Happy holidays!

  5. ShaneK commented on Dec 31, 2025

    @ShaneK
    Member

    I tried version 8.7.16-dev.11767019759.14b7f2fa and the same thing happens.

    Yeah, I was getting back to looking at this this morning and realized I was wrong, sorry. My PR was intended to address an issue with iOS. I'm gonna look into this as part of that solution though, since it's all pretty related.

  6. ShaneK commented on Dec 31, 2025

    @ShaneK
    Member

    @Marius-Romanus could you try my new dev buld, 8.7.16-dev.11767205737.13557925 and see if that works for you?

  7. Marius-Romanus commented on Jan 1, 2026

    @Marius-Romanus
    Author

    Hi, it seems to work fine with the example, but it doesn't work in my actual project and I haven't figured out why yet.

    Edit:
    I think it has to do with the fact that in many cases I have it programmatically with controllers in different componentsand presentingElement when loading them:

    presentingElement: await this.modalController.getTop()
    or
    presentingElement: this.ionRouterOutlet.parentOutlet?.nativeEl

    modalController = inject(ModalController);
    popoverController = inject(PopoverController);
    
    this.modalController.create({ ...
    this.popoverController.create({ ...
    
  8. ShaneK commented on Jan 2, 2026

    @ShaneK
    Member

    Could you try with this dev build?

    8.7.16-dev.11767365495.141917e9
    
  9. Marius-Romanus commented on Jan 3, 2026

    @Marius-Romanus
    Author

    Hi, it seems that in this version 8.7.16-dev.11767365495.141917e9 it doesn't display correctly at the top.

    Image

    And in my actual app, the bottom part still looks bad, and it jumps strangely between looking good and bad.

  10. ShaneK commented on Jan 5, 2026

    @ShaneK
    Member

    Can you please provide a reproduction of your app's setup that wasn't working with the previous implementation? It's pretty rough trying to troubleshoot this blind

  11. ionitron-bot commented on Jan 5, 2026

    @ionitron-bot

    Thanks for the issue! This issue has been labeled as needs reproduction. This label is added to issues that need a code reproduction.

    Please reproduce this issue in an Ionic starter application and provide a way for us to access it (GitHub repo, StackBlitz, etc). Without a reliable code reproduction, it is unlikely we will be able to resolve the issue, leading to it being closed.

    If you have already provided a code snippet and are seeing this message, it is likely that the code snippet was not enough for our team to reproduce the issue.

    For a guide on how to create a good reproduction, see our Contributing Guide.

  12. 15 remaining items

  13. ShaneK commented on Jan 7, 2026

    @ShaneK
    Member

    Hey! I'm not seeing any way to reproduce any issues with the footer, I'm afraid I'm gonna need more information to go on.

  14. Marius-Romanus commented on Jan 8, 2026

    @Marius-Romanus
    Author

    I'm having trouble finding the examples because I'm not sure what values ​​they depend on. I'm trying to replicate what I have in my app to get them, but it doesn't always work, and I don't know why.

    I've updated the example in tab 3 with a Kanban simulation.

    Image

    And in my actual app, which I haven't been able to replicate (I'm trying in tab 2 of the example), in the footer, but only in the first tab, it's adding the class "safe-area-bottom" to ion-content.

    Image

    Here's the structure in case it helps: body > app-root > ion-app > ion-router-outlet > app-dashboard > ion-tabs > div > ion-router-outlet > app-notes > ion-content


    And a simple list where the footer looks wrong, and I don't know why. I've also tried to replicate it in the example without success.

    Image

    Here's the structure in case it helps: body > app-root > ion-app > ion-router-outlet > app-dashboard > ion-tabs > div > ion-router-outlet > app-labels > ion-content

  15. ShaneK commented on Jan 8, 2026

    @ShaneK
    Member

    Edit: Don't use the one I just posted, there's some tests flagging issues I need to look at real quick

  16. ShaneK commented on Jan 8, 2026

    @ShaneK
    Member

    Okay, got all of that sorted! Please try again with this new dev build:

    8.7.17-dev.11767897190.1ef0f479
    

    There's so many edge cases in this one, sorry about how long it's taking

  17. Marius-Romanus commented on Jan 9, 2026

    @Marius-Romanus
    Author

    Ugh, it was hard to reproduce. I think it's a reactivity issue.

    First, sorry for the messy code I'm using in the demo. I'm having a hard time figuring out why things are happening, and I'm just trying things out randomly.

    I created a route called lists2 in the routes, at the same level as the tabs. In the tabs' HTML, I put an if statement that relies on a signal computed() function to check if the routes file contains the snapshot flag data: { tabs: true } to determine whether or not to display it.

    Click on the link: Router List 2 and you'll see the error in the footer.

    I think it's the cause of both the incorrect padding at the beginning and the missing padding in the list (as in the example).

    Image Image

    There's so many edge cases in this one, sorry about how long it's taking

    We make a good team 💪, it's always good to help the community. Updated demo :)

  18. ShaneK commented on Jan 9, 2026

    @ShaneK
    Member

    Hey! I see, looks like when tabs are hidden dynamically we need to re-check safe areas. I have a dev build here if you'd like to try it out:

    8.7.17-dev.11767980394.1d9266a9
    
  19. Marius-Romanus commented on Jan 9, 2026

    @Marius-Romanus
    Author

    Perfect! The only thing missing, I think, is adding the safe-area to the sides of ion-content when you lay the phone flat.

    Image
  20. ShaneK commented on Jan 9, 2026

    @ShaneK
    Member

    Alright! I think this one should work. Here's the dev build:

    8.7.17-dev.11767984108.1f9159e1
    

    Please let me know how it goes!

  21. Marius-Romanus commented on Jan 9, 2026

    @Marius-Romanus
    Author

    It seems that now in the lists, the padding extends further inwards.

    Image

    I understand that these kinds of style issues are separate from this particular problem and represent new features.

    There are some design aspects that I imagine you'll have to improve in the future, for example, the progress bar... should it be cropped or expanded from side to side?

    Image

    Also, it's noticeable that the maps often extend to the edge. I imagine you'll have to add a new option to ion-content to define whether you want them edge-to-edge or with padding, depending on your specific use case, such as when it's laid flat on both sides or if, for example, it doesn't have a footer or header.

    Image Image
  22. ShaneK commented on Jan 12, 2026

    @ShaneK
    Member

    Hey! I'm actually going to pull back on a lot of these changes because this has sort of spiraled into a series of unrelated changes to the original PR. I'm going to focus my PR on dealing with popovers and modals and we'll have to come back around at a later time to look at the other issues. I think some of these changes will require a bit more investigation than should be done for the patch I'm currently working on, unfortunately. So with these changes, I'd expect a lot of your concerns around modals and popovers to be fixed, but the other changes around unsupported safe areas will be undone for now to prevent unexpected issues with components that are already trying to support safe areas.

    Here's the current dev build:

     8.7.17-dev.11768239180.18ee1069
    

    I really appreciate you iterating on me with this and highlighting these issues. Sorry I wasn't able to get the other issues addressed at this time.

  23. Marius-Romanus commented on Jan 12, 2026

    @Marius-Romanus
    Author

    Okay, perfect, I'll wait for the patch then to update my app

  24. Marius-Romanus commented on Feb 17, 2026

    @Marius-Romanus
    Author

    Hi @ShaneK, is there any progress on this? Until it's working properly, we can't update to API 36.

  25. ShaneK commented on Feb 17, 2026

    @ShaneK
    Member

    Hey! Last week I merged this PR, which should address the popover and modal issues:
    #30949

  26. Marius-Romanus commented on Feb 17, 2026

    @Marius-Romanus
    Author

    And any progress on tabs and ion-content?

  27. Marius-Romanus commented on Mar 16, 2026

    @Marius-Romanus
    Author

    Hi again @ShaneK

    I've been testing everything again, with the latest version of everything, including @ionic/angular: 8.8.1, and it seems to work fine, except when it's a new route with an ion-header and an ion-content. 😬😬😬

    Edit:

    Okay... it wasn't the only place. I've seen another bug, two padding-bottom elements are being used in:

    ion-modal>.ion-page {
        position: relative;
        contain: layout style;
        height: 100%;
    }
    <style>
    [_nghost-ng-c2692105282] {
        padding-bottom: var(--ion-safe-area-bottom);
    }
    .ion-page {
        inset: 0;
        display: flex;
        position: absolute;
        flex-direction: column;
        justify-content: space-between;
        contain: layout size style;
        z-index: 0;
    }
    

    and bottom is added here:

    <div role="dialog" aria-modal="true" class="modal-wrapper ion-overlay-wrapper" part="content" style="height: calc(var(--height) - var(--ion-safe-area-bottom, 0px));padding-bottom: var(--ion-safe-area-bottom, 0px);"><slot></slot></div>

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

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions