Skip to content
Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More

StaggeredGrid

A masonry (waterfall) grid layout that places items into columns of equal width and lets each item’s height vary naturally, eliminating the uniform-height constraint of standard grids. Native handlers deliver high-performance scrolling on every platform.

  • NuGet downloads for Shiny.Maui.Controls
  • NuGet downloads for Shiny.Blazor.Controls
Frameworks
.NET MAUI
Blazor
  • Variable-Height Items — Each item fills its natural height; the next item is placed in the shortest column, producing the classic Pinterest waterfall effect.
  • Configurable Column Count — Set ColumnCount to any integer to control the number of columns.
  • Native Handlers — Android: RecyclerView with StaggeredGridLayoutManager; iOS: custom WaterfallLayout (UICollectionViewLayout); Windows: WaterfallVirtualizingLayout; Blazor: CSS column-count.
  • Empty View — Provide an EmptyViewTemplate / EmptyTemplate to render a placeholder when the data source is empty.
  • Item SelectionItemSelectedCommand (MAUI) and ItemSelected (Blazor) surface tap/click interactions.
claude plugin marketplace add shinyorg/skills
claude plugin install shiny-client@shiny
BLE, GPS, Jobs, Notifications, Push, HTTP Transfers, OBD, Music, Health, DataSync — iOS, Android, Windows, MacOS, Linux, Web
claude plugin install shiny-maui@shiny
Shell, Contact Store
claude plugin install controls@shiny
TableView, BottomSheet, PillView, ImageViewer, Scheduler, Markdown, Mermaid Diagrams — MAUI and Blazor
claude plugin install shiny-mediator@shiny
Mediator/CQRS with middleware and source generators
claude plugin install shiny-data@shiny
DocumentDB and Spatial data libraries
claude plugin install shiny-aspire@shiny
Orleans and Gluetun Aspire integrations
claude plugin install shiny-extensions@shiny
DI, Stores, Reflector, Localization, Hosting modules
copilot plugin marketplace add https://github.com/shinyorg/skills
copilot plugin install shiny-client@shiny
BLE, GPS, Jobs, Notifications, Push, HTTP Transfers, OBD, Music, Health, DataSync — iOS, Android, Windows, MacOS, Linux, Web
copilot plugin install shiny-maui@shiny
Shell, Contact Store
copilot plugin install controls@shiny
TableView, BottomSheet, PillView, ImageViewer, Scheduler, Markdown, Mermaid Diagrams — MAUI and Blazor
copilot plugin install shiny-mediator@shiny
Mediator/CQRS with middleware and source generators
copilot plugin install shiny-data@shiny
DocumentDB and Spatial data libraries
copilot plugin install shiny-aspire@shiny
Orleans and Gluetun Aspire integrations
copilot plugin install shiny-extensions@shiny
DI, Stores, Reflector, Localization, Hosting modules
View Skills Repository
<shiny:StaggeredGrid ItemsSource="{Binding Photos}"
ColumnCount="2"
ColumnSpacing="8"
RowSpacing="8"
ItemSelectedCommand="{Binding OpenPhotoCommand}">
<shiny:StaggeredGrid.ItemTemplate>
<DataTemplate>
<Border StrokeShape="{RoundRectangle CornerRadius=8}">
<Image Source="{Binding Url}" Aspect="AspectFill" />
</Border>
</DataTemplate>
</shiny:StaggeredGrid.ItemTemplate>
<shiny:StaggeredGrid.EmptyViewTemplate>
<DataTemplate>
<Label Text="No photos yet" HorizontalOptions="Center" />
</DataTemplate>
</shiny:StaggeredGrid.EmptyViewTemplate>
</shiny:StaggeredGrid>
<StaggeredGrid Items="photos"
ColumnCount="2"
ColumnSpacing="16"
RowSpacing="16"
ItemSelected="OnPhotoSelected">
<ItemTemplate Context="photo">
<div class="photo-card">
<img src="@photo.Url" alt="@photo.Title" />
</div>
</ItemTemplate>
<EmptyTemplate>
<p>No photos yet.</p>
</EmptyTemplate>
</StaggeredGrid>
@code {
List<Photo> photos = [];
void OnPhotoSelected(Photo photo) { }
}
PropertyMAUI TypeBlazor TypeDefaultDescription
ItemsSource / ItemsIEnumerableIReadOnlyList<TItem>Collection of items to display
ItemTemplateDataTemplateRenderFragment<TItem>Template for each grid item
EmptyViewTemplate / EmptyTemplateDataTemplateRenderFragmentContent shown when the source is empty
ColumnCountintint2Number of masonry columns
ColumnSpacingdoubledouble— / 16Horizontal gap between columns in px
RowSpacingdoubledouble— / 16Vertical gap between items in px

MAUI:

  • ItemSelectedCommand (ICommand) — Fired when a grid item is tapped; parameter is the selected item

Blazor:

  • ItemSelected (EventCallback<TItem>) — Fired when a grid item is clicked/tapped
  • Items are distributed into columns using a shortest-column-first algorithm so column heights stay balanced
  • On iOS, if the root view of the ItemTemplate has an explicit HeightRequest, it is used directly for layout measurement. This is the most reliable approach for items with remote images or async content
  • ColumnCount changes at runtime trigger a full layout pass
  • When ItemsSource / Items is null or empty, EmptyViewTemplate / EmptyTemplate is rendered in its place
  • ColumnSpacing applies between columns; RowSpacing applies between items within a column