Skip to content

feat(grid, row, col): add recipe and tokens#31189

Merged
thetaPC merged 25 commits into
ionic-modularfrom
FW-6868
Jun 5, 2026
Merged

feat(grid, row, col): add recipe and tokens#31189
thetaPC merged 25 commits into
ionic-modularfrom
FW-6868

Conversation

@thetaPC
Copy link
Copy Markdown
Contributor

@thetaPC thetaPC commented Jun 3, 2026

Issue number: resolves internal


What is the current behavior?

ion-grid, ion-row, and ion-col do not fragment styles based on themes.

What is the new behavior?

  • Migrates ion-grid, ion-row, and ion-col to Modular Ionic.
  • Adds IonGridRecipe, IonColRecipe, and IonRowRecipe, plus per-theme token defaults in the ios, md, and ionic theme files.
  • Reworks grid and column padding and the fixed-grid width into the per-breakpoint, per-side --ion-grid-breakpoint-* / --ion-col-breakpoint-* naming, and adds --ion-row-gap for row spacing.
  • Makes ion-col spans adjustable: size, offset, and order are written as inline custom properties (--internal-col-span, --internal-col-margin, order) so any --ion-grid-columns value resolves correctly, removing the build-time 12-column cap.
  • Renames the internal classes to col-size, col-auto, and col-offset, and adds IonColProperty / IonColStyle types.

Does this introduce a breaking change?

  • Yes
  • No

This PR introduces breaking changes to how ion-grid, ion-row, ion-col are styled.

Migration Path:

  1. Grid padding: was a single value per breakpoint, now per-side:
Old Token (global) CSS variable (component-specific)
--ion-grid-padding-{bp} IonGrid.breakpoint.{bp}.padding.{top|end|bottom|start} --ion-grid-breakpoint-{bp}-padding-{top|end|bottom|start}
  1. Grid fixed width
Old Token (global) CSS variable (component-specific)
--ion-grid-width-{bp} IonGrid.breakpoint.{bp}.width --ion-grid-breakpoint-{bp}-width
  1. Column padding: renamed into the col namespace and now per-side:
Old Token (global) CSS variable (component-specific)
--ion-grid-column-padding-{bp} IonCol.breakpoint.{bp}.padding.{top|end|bottom|start} --ion-col-breakpoint-{bp}-padding-{top|end|bottom|start}
  1. Theme classes: Remove any instances that target the theme classes: ion-grid.md, ion-grid.ios, ion-row.md, ion-row.ios, ion-col.md, ion-col.ios

Other information

Previews

@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 3, 2026

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

Project Deployment Actions Updated (UTC)
ionic-framework Ready Ready Preview, Comment Jun 5, 2026 10:21pm

Request Review

@github-actions github-actions Bot added package: core @ionic/core package package: angular @ionic/angular package labels Jun 3, 2026
--col-unit-size: calc(
(100% - (var(--ion-grid-columns, 12) - 1) * var(--ion-grid-gap, 0px)) / var(--ion-grid-columns, 12)
--internal-col-unit-size: calc(
(100% - (var(--ion-grid-columns, 12) - 1) * var(--ion-row-gap, 0px)) / var(--ion-grid-columns, 12)
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 changed --ion-grid-gap to --ion-row-gap since the value is adding the gap on row, not gap. No need to add it to the breaking changes since this variable was introduced in next.

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 was added for Mobile UI so we likely need a follow-up ticket for them to update it if they are using it.

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.

FW-7563 created!

}

:host(.ion-grid-col-auto) {
:host(.col-auto) {
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.

No need to add it to the breaking changes since this class was introduced in next.

Comment on lines -67 to -80
$grid-col-number: 12;

@for $i from 1 through $grid-col-number {
:host(.ion-grid-col--#{$i}) {
--ion-grid-col-span: #{$i};
}

:host(.ion-grid-order-col--#{$i}) {
order: #{$i};
}

:host(.ion-grid-offset-col--#{$i}) {
--ion-grid-col-margin: #{$i};
}
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.

Previously, a @for 1 through 12 loop generated a fixed set of per-column classes (ion-grid-col--1…--12, plus order/offset variants), each hardcoding the span/order/offset multiplier. Because the loop ran at Sass compile time, the supported column count was capped at 12 — yet the width math already divided by the runtime --ion-grid-columns, so a grid with more than 12 columns (e.g. --ion-grid-columns: 16 + size="16") produced a class with no matching rule, leaving --internal-col-span unset and invalidating the calc(). col.tsx now writes the span, offset, and order as inline custom properties from the parsed attribute value, so any column count composes with the --ion-grid-columns divisor without a build-time class cap. The generated classes (and $grid-col-number) are no longer needed.

shadow: true,
})
export class Col implements ComponentInterface {
private resizeTimeout: ReturnType<typeof setTimeout> | null = null;
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.

Added a debounced window-resize handler so the column re-renders when the viewport crosses a responsive breakpoint — Stencil won't re-render on media-query changes on its own, so getColumns()'s matchBreakpoint() result would otherwise go stale. resizeTimeout holds the debounce handle so rapid resize events collapse into a single forceUpdate, and so the pending timer can be cleared in disconnectedCallback. This mirrors the established pattern in other components such as ion-content, which uses the same resizeTimeout + debounced forceUpdate approach on window resize.

</ion-row>
</ion-grid>

<h2 class="ion-padding-start">Offset</h2>
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.

These were removed because the same copy exists in the basic test.

};
};

columns?: number;
Copy link
Copy Markdown
Contributor Author

@thetaPC thetaPC Jun 3, 2026

Choose a reason for hiding this comment

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

Should this be a prop instead to match ion-gallery? I think we should to be consistent. If so, then a new ticket should be created to do the overhaul.

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.

Yes. Grid needs a complete overhaul.

@@ -0,0 +1,3 @@
export type IonRowRecipe = {
gap?: string;
Copy link
Copy Markdown
Contributor Author

@thetaPC thetaPC Jun 3, 2026

Choose a reason for hiding this comment

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

Should this be a prop instead to match ion-gallery? I think we should to be consistent. If so, then a new ticket should be created to do the overhaul.

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.

Yes. Grid needs a complete overhaul.


@ProxyCmp({
inputs: ['mode', 'offset', 'offsetLg', 'offsetMd', 'offsetSm', 'offsetXl', 'offsetXs', 'order', 'orderLg', 'orderMd', 'orderSm', 'orderXl', 'orderXs', 'pull', 'pullLg', 'pullMd', 'pullSm', 'pullXl', 'pullXs', 'push', 'pushLg', 'pushMd', 'pushSm', 'pushXl', 'pushXs', 'size', 'sizeLg', 'sizeMd', 'sizeSm', 'sizeXl', 'sizeXs', 'theme']
inputs: ['mode', 'offset', 'offsetLg', 'offsetMd', 'offsetSm', 'offsetXl', 'offsetXs', 'order', 'orderLg', 'orderMd', 'orderSm', 'orderXl', 'orderXs', 'pull', 'pullLg', 'pullMd', 'pullSm', 'pullXl', 'pullXs', 'push', 'pushLg', 'pushMd', 'pushSm', 'pushXl', 'pushXs', 'size', 'sizeLg', 'sizeMd', 'sizeSm', 'sizeXl', 'sizeXs']
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 think we should convert order and offset to accept an object like how columns does with ion-gallery. This would allow us to set the breakpoints through one value instead. Thoughts? I can create a ticket if we agree.

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.

Yes. Grid needs a complete overhaul.

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 replaced ion-grid to native grid so we don't have to always update snapshots if ion-grid changed.

f {
display: block;
width: 100%;
.color-grid {
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 replaced ion-grid to native grid so we don't have to always update snapshots if ion-grid changed.

<ion-col size="6"><f class="orange"></f></ion-col>
</ion-row>
</ion-grid>
<div class="color-grid">
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 replaced ion-grid to native grid so we don't have to always update snapshots if ion-grid changed.

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 replaced ion-grid to native grid so we don't have to always update snapshots if ion-grid changed.

translucent variant) is visible over varied colors. Uses native CSS
grid instead of ion-grid so this page's snapshots don't churn when
grid/row/col change. */
.color-grid {
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 replaced ion-grid to native grid so we don't have to always update snapshots if ion-grid changed.

@thetaPC thetaPC merged commit eed7167 into ionic-modular Jun 5, 2026
88 of 94 checks passed
@thetaPC thetaPC deleted the FW-6868 branch June 5, 2026 22:52
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.

3 participants