Skip to content

[SDK-500] Follow the system light/dark theme in HTML in-app messages - #1084

Open
franco-zalamena-iterable wants to merge 4 commits into
masterfrom
feature/SDK-500-inapp-daynight-theme
Open

[SDK-500] Follow the system light/dark theme in HTML in-app messages#1084
franco-zalamena-iterable wants to merge 4 commits into
masterfrom
feature/SDK-500-inapp-daynight-theme

Conversation

@franco-zalamena-iterable

@franco-zalamena-iterable franco-zalamena-iterable commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

HTML in-app messages now follow the host activity's Android light/dark configuration instead of always rendering as if the device were in dark mode.

Jira ticket: SDK-500

Description

A campaign with an @media (prefers-color-scheme: dark) block rendered its dark styles even in light mode. WebView takes prefers-color-scheme from the isLightTheme attribute of its context's theme, and both in-app containers were pinned to a non-DayNight AppCompat theme (always dark). On top of that, the fragment path built its WebView from the host activity instead of the dialog, so fixing the theme alone did nothing.

Both containers now use a DayNight theme and the WebView gets the dialog's context. In the default AUTOMATIC mode, the in-app follows the host activity's Android UI mode.

Apps that keep their theme only in Compose state can configure IterableConfig.Builder.setInAppColorScheme() for a fixed override or setInAppColorSchemeProvider() for a value that is evaluated whenever an in-app message is created.

Documentation is staged on the Iterable/iterable-docs branch
docs/sdk/september-release in commit b6cfb52cc. The documentation PR will
be opened with the September SDK release.

Worth calling out: in AUTOMATIC mode, an app with a hard-coded light theme running on a dark-mode device gets a dark in-app. Apps that need the in-app to follow a separately managed theme can use the explicit override.

This development was started by contributor @AndrazP.

Addresses #1056 and supersedes #1057, which only covered the fragment path. The Dialog path used by Compose apps (#1015) had the same problem.

Docs branch created for the september release: https://github.com/Iterable/iterable-docs/tree/docs/sdk/september-release

SDK-500-before-after.mp4

HTML in-app messages always reported prefers-color-scheme: dark to the
campaign HTML, so a campaign with an @media (prefers-color-scheme: dark)
block rendered its dark styles even on a light-mode device.

Two things combined, and either fix alone is inert:

- Both in-app containers hard-coded a dark, non-DayNight AppCompat theme,
  so isLightTheme resolved false regardless of the configuration.
- The fragment path built its WebView from the host activity context
  rather than the dialog's themed context.

Reparent both containers onto Theme.AppCompat.DayNight.NoActionBar and
give the fragment path's WebView the dialog context. DayNight resolves
from the configuration uiMode, which is also what
AppCompatDelegate.setDefaultNightMode manipulates - the analogue of iOS,
where WKWebView inherits the system trait collection.

Dark mode is unchanged: DayNight resolves to Theme.AppCompat.NoActionBar
under values-night, which is the theme in use today.

This development was started by contributor @AndrazP.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@franco-zalamena-iterable
franco-zalamena-iterable requested a review from a team as a code owner August 25, 2026 10:14

@joaodordio joaodordio left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a comment regarding the composer support and we also need a docs PR to cover these changes plz!

Other than that, all good!

this.messageId = "";
insetPadding = new Rect();
this.setStyle(DialogFragment.STYLE_NO_FRAME, androidx.appcompat.R.style.Theme_AppCompat_NoActionBar);
this.setStyle(DialogFragment.STYLE_NO_FRAME, androidx.appcompat.R.style.Theme_AppCompat_DayNight_NoActionBar);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the right fix for apps that follow the system or use AppCompatDelegate.setDefaultNightMode, but it leaves Compose apps that keep their theme in Compose state with no way to influence it.

A Compose app on a light-mode device with the user set to dark currently gets a dark in-app and will get a light one after this. The Dialog path exists for exactly those apps (#1015), so I don't think we can ship this without either an IterableConfig override for the in-app color scheme, or an explicit docs note telling those integrators to call setDefaultNightMode. Which one do you think it's better? Or am I missing something on the Compose support side?

@franco-zalamena-iterable franco-zalamena-iterable Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I tested the documentation-only AppCompatDelegate.setDefaultNightMode option against the pure ComponentActivity path, and the dialog stayed light, so that would not reliably cover Compose-managed theme state.

I added an explicit config API in c34ff01:

  • setInAppColorScheme() for a fixed AUTOMATIC/LIGHT/DARK value
  • setInAppColorSchemeProvider() for Compose state; it is queried whenever an in-app container is created

The tests cover explicit overrides on both the Fragment and Dialog renderers and changing the provider value between two Dialog in-apps. The documentation is staged in Iterable/iterable-docs on docs/sdk/september-release at b6cfb52cc; its PR will be opened with the September SDK release.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

In-app HTML messages ignore system light/dark theme on Android

3 participants