Skip to content

feat(content): add recipe and tokens#31095

Open
thetaPC wants to merge 23 commits intoionic-modularfrom
FW-6896
Open

feat(content): add recipe and tokens#31095
thetaPC wants to merge 23 commits intoionic-modularfrom
FW-6896

Conversation

@thetaPC
Copy link
Copy Markdown
Contributor

@thetaPC thetaPC commented Apr 24, 2026

Issue number: resolves internal


What is the current behavior?

ion-content does not fragment styles based on themes. All 3 themes share one style. However, it's not configured to the Modular Ionic.

What is the new behavior?

  • Defined TypeScript Interface: Renamed content-interface.ts to content.interfaces.ts and added IonContentRecipe type.
  • Defined Theme Defaults: Added per-theme token defaults in ios, md, and ionic theme files.
  • Internal Variable Prefix: Renamed --offset-top / --offset-bottom to --internal-offset-top / --internal-offset-bottom to clearly separate them from the public CSS API.
  • CSS Logical Properties for RTL: Replaced physical-property RTL selectors on .transition-effect and .transition-shadow with the position-horizontal mixin.
  • Removed dead property: Dropped -webkit-overflow-scrolling: touch from styles as this property has been a no-op since iOS 13.
  • Updated Tests: Added unit specs for transitionShadow (present in ios mode, absent in md mode) and the getScrollElement() / getBackgroundElement() element ref methods.
  • New utility: Replaced inline new Promise((resolve) => componentOnReady(...)) patterns with a shared waitForComponent helper, reducing boilerplate and improving type safety.

Does this introduce a breaking change?

  • Yes
  • No

This PR introduces breaking changes to how ion-content is styled.

Migration Path:

  1. CSS Variable Replacements: --background and --color have been removed. Use the new token structure:
--background -> IonContent.background
--color -> IonContent.color

--padding-* is still supported. .ion-padding, .ion-padding-* classes in css/padding.scss set --padding-* directly on the host. ion-content continues to honor those values (falling back to the new token when unset). Existing usage of the utility classes and direct --padding-* overrides will keep working.

New code is encouraged to use the token-based API instead:

--padding-top -> IonContent.padding.top
--padding-end -> IonContent.padding.end
--padding-bottom -> IonContent.padding.bottom
--padding-start -> IonContent.padding.start

Note: core/api.txt only lists the new --ion-content-padding-* variables. The --padding-* overrides remain functional but are no longer part of the documented public API.

If per-component customization is needed, the CSS variables can be used directly.

--background -> --ion-content-background
--color -> --ion-content-color
--padding-top -> --ion-content-padding-top
--padding-end -> --ion-content-padding-end
--padding-bottom -> --ion-content-padding-bottom
--padding-start -> --ion-content-padding-start
  1. Internal-only variables (no replacement): The following CSS variables were previously documented @props on ion-content and have been renamed to the --internal-* namespace, removing them from the public API:
--keyboard-offset -> --internal-keyboard-offset
--offset-top      -> --internal-offset-top
--offset-bottom   -> --internal-offset-bottom

These are managed by ion-content itself (keyboard avoidance and header/footer offsets) and were never intended for consumer override. There is no replacement - any code that was setting them directly should be removed.

  1. Theme classes: Remove any instances that target the theme classes: ion-content.md, ion-content.ios.

Other information

Previews:

The framework (Angular, React, Vue) test apps are not being styled correctly anymore because the new tokens are not being passed to them. This is expected until we can export the tokens as mentioned in the design doc. The functionality in those test apps are still working.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ionic-framework Ready Ready Preview, Comment May 6, 2026 11:19pm

Request Review

flex-shrink: 2;
overscroll-behavior-y: contain;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
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.

-webkit-overflow-scrolling has become obsolete since iOS 13.

contain: size style;
}

:host(.ion-color) .inner-scroll {
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.

There seems to be a lot deleted, but they were just moved around in the file.

@Method()
async getBackgroundElement(): Promise<HTMLElement> {
if (!this.backgroundContentEl) {
await new Promise((resolve) => componentOnReady(this.el, resolve));
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.

Created a util for this since a lot of components are using the same code

...customTheme.palette,
},
};
theme = deepMerge(theme, customTheme);
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.

This change mimics exactly how we are loading themes in the theme.ts file.

Comment on lines +49 to +52
$padding-top: var(--padding-top, var(--ion-content-padding-top, 0px));
$padding-end: var(--padding-end, var(--ion-content-padding-end, 0px));
$padding-bottom: var(--padding-bottom, var(--ion-content-padding-bottom, 0px));
$padding-start: var(--padding-start, var(--ion-content-padding-start, 0px));
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.

In order for the padding classes (.ion-padding) to still be functional, we should be incorporating them as the first check.

:host(.ion-color) .inner-scroll {
background: color.current-color(base);
color: color.current-color(contrast);
}
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.

I didn't make this customizable because all themes are using the same styles. If the community requests it, then we can update the recipe to include it.

}

.transition-shadow {
@include mixins.position-horizontal(null, 0);
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.

We can now use this mixin instead of having to use left/right!

@thetaPC thetaPC marked this pull request as ready for review May 5, 2026 15:37
@thetaPC thetaPC requested a review from a team as a code owner May 5, 2026 15:37
@thetaPC thetaPC requested a review from gnbm May 5, 2026 15:37
@thetaPC thetaPC marked this pull request as draft May 5, 2026 16:58

:host(.ion-color) .inner-scroll {
background: color.current-color(base);
color: color.current-color(contrast);
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.

I was going to switch this to use foreground as stated in the ticket but that lead to unwanted changes like:

Image

The text color is not readable in some components. Others, it's too light and I question if it would pass accessibility.

Image

We should look into the foreground values again.

@thetaPC thetaPC marked this pull request as ready for review May 5, 2026 18:09
Copy link
Copy Markdown
Member

@ShaneK ShaneK left a comment

Choose a reason for hiding this comment

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

Looking awesome! Mostly just have a few clarafication/documentation questions

Comment thread core/src/components/content/content.scss
Comment thread core/src/css/core.scss Outdated
Comment thread core/src/components/content/content.scss
Comment thread core/src/components/content/content.scss Outdated
Comment thread core/src/themes/ios/default.tokens.ts Outdated
@thetaPC thetaPC requested review from ShaneK and removed request for gnbm May 7, 2026 00:53
Copy link
Copy Markdown
Member

@ShaneK ShaneK left a comment

Choose a reason for hiding this comment

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

Looks good to me! Just a question and a nit, but non-blocking

Comment thread core/src/global/config.ts
* @returns The value found at the nested key or the fallback
*/
getObjectValue(key: string, fallback?: string): string | undefined {
getObjectValue(key: string, fallback?: ObjectConfigValue): ObjectConfigValue | undefined {
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.

Are there callers lined up that need the boolean return? I couldn't find any consumers of getObjectValue, so widening from string | undefined to string | boolean | undefined reads as pre-emptive. If a follow-up PR needs it, that's cool, just checking.

}

.transition-shadow {
@include mixins.position-horizontal(null, 0);
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.

Nit: .transition-effect and .transition-shadow got converted to mixins.position-horizontal(...), but .transition-cover at line 245 still uses literal right: 0 with stylelint-disable. Full-width so RTL behavior is identical, but is leaving the asymmetric pattern intentional?

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

Labels

package: angular @ionic/angular package package: core @ionic/core package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants