The MainGrid component is a standalone grid for displaying Dataverse records. Unlike SubGrid, it does not require a parent RecordContext — it loads records directly from a specified table or view.
Live Demo
A standalone MainGrid over the contact table wired to two custom views — Active Contacts and My Contacts. Use the view-picker dropdown to switch between them, type in the search box to filter, click a column header to sort, and use the footer to page through results. No parent RecordContext is required — the grid loads its records directly from the supplied views.
React example
Blazor example
Anyone can view contacts in the grid below. Log in to create, view, and update your own contacts.
All ContactsMy Contacts
All ContactsMy Contacts
Page size
102050100
Full Name
Mobile Phone
Email
Company Name
Age
Abagail Miller
(501) 801-9303
Abagail_Miller30@yahoo.com
Lowe Inc
52
Abdul Pollich
(319) 579-4439
Abdul73@yahoo.com
Wiza, Bradtke and Hintz
54
Abel Parisian
(631) 444-9854
Abel84@gmail.com
Raynor - Lakin
32
Abigale Kuvalis
(369) 810-9954
Abigale71@gmail.com
Murazik Group
65
Adell Paucek
(260) 615-0566
Adell99@yahoo.com
Windler, Toy and D'Amore
40
Adella Roob
(535) 638-9390
Adella.Roob88@hotmail.com
Pollich - Kling
39
Adolf Weber
(978) 300-6533
Adolf.Weber10@gmail.com
West Group
20
Adonis Torphy
(842) 804-9308
Adonis_Torphy35@hotmail.com
Mohr and Sons
58
Agustin Goyette
(374) 932-0000
Agustin_Goyette@gmail.com
Lebsack, Homenick and Carter
25
Agustin Rau
(986) 867-9045
Agustin_Rau@gmail.com
Lehner Group
22
React TypeScript
Razor
Loading by Table Name
Set the TableName parameter to automatically load all public views for that table. The first default view is selected initially.
React
<MainGrid tableName="contact" />Blazor
<MainGrid TableName="contact" />
Loading by View IDs
Use ViewIds and DefaultViewId to control exactly which views are available and which one is selected on load. You can also provide CustomViewDefinitions with inline FetchXML to define views directly in code.
<MainGrid ViewIds="_viewIds"
DefaultViewId="@(new Guid("..."))">
</MainGrid>
@code {
private List<Guid> _viewIds = new List<Guid>
{
new Guid("..."),
new Guid("..."),
};
}
Custom Views with FetchXML
Use CustomViewDefinitions to define views with custom FetchXML queries. This is useful for views that include filters based on the current user, linked entities, or other dynamic criteria.
Note
The Id for a custom GridViewDefinition must be a unique random GUID that does not correspond to an existing Dataverse view. If it matches an existing view ID, the Dataverse view will take precedence and the custom definition will be ignored.
private List<GridViewDefinition> _customViews = new List<GridViewDefinition>
{
new GridViewDefinition
{
Id = new Guid("..."),
TableName = "contact",
DisplayName = "All Contacts",
FetchXml = @"<fetch>
<entity name='contact'>
<attribute name='fullname' />
<attribute name='emailaddress1' />
<order attribute='fullname' />
</entity>
</fetch>",
Columns = new List<ViewColumn>
{
new ViewColumn { ColumnName = "fullname", Width = 200 },
new ViewColumn { ColumnName = "emailaddress1", Width = 250 },
}
}
};
DisplayName
Set DisplayName on a GridViewDefinition to provide a default label for the view in the dropdown selector without requiring a localization file entry. If a localization key exists at tables.{TableName}.views.{Id}.label, it takes precedence over DisplayName. This is useful for custom views where you want a readable name immediately without adding a localization entry.
Toolbar Buttons
The MainGrid supports the same toolbar buttons as SubGrid. For standalone grids, NavigateNewRecordGridButton and NavigateOpenRecordGridButton are commonly used to navigate to separate form pages. See the Grid Buttons documentation for a complete reference of all available buttons and their configuration options.
When the user types in the grid's search box, the configured view is automatically re-queried with additional filter conditions applied to every search-eligible column shown in the view. The conditions are joined with OR logic, so a record is included if any of its visible columns match the search term. The default match semantics differ depending on the column type.
Text and Lookup Columns
Text columns (string fields) and lookup columns (matched against the target record's primary name) use a starts with search by default. Typing joh matches values that begin with joh — for example John or Johnson. The match is delegated to FetchXML's like operator, which is case-insensitive in Dataverse.
Use * as a wildcard for more flexible matching. Typing *hn performs a contains-style match (e.g. John, Johnson); typing j*n matches values where any characters can appear between the j and the n (e.g. John, Joneson). The wildcard is converted to FetchXML's % wildcard at query time.
Choice Columns
Choice columns (option sets / picklists) and multi-select choice columns are matched against the localized display label of each option rather than the underlying integer value. Labels are compared case- and accent-insensitively in the current user's culture, so typing cafe will match an option labelled Café. When one or more option labels match, the query emits a FetchXML condition against the matching option values — an in condition for single-select choice columns, or a contain-values condition for multi-select choice columns. When no labels match, the column contributes no condition (keeping the OR filter compact).
Choice columns honor the same * wildcard as text columns: by default the match is starts with (typing act matches Active), and a leading * switches to contains (typing *act additionally matches Inactive). Matching rows have the matched substring highlighted in the grid, exactly like text-column matches.
Numeric and Money Columns
Numeric columns — int, big int, decimal, double, and money — support comparison operators in the search term. The search box parses an optional leading operator and applies the corresponding FetchXML condition operator:
= 100 or just 100 — equal (the default when no operator is specified)
> 100 — greater than
< 100 — less than
>= 100 — greater than or equal
<= 100 — less than or equal
Note
Search conditions for every column type are added to the same OR filter group, so the same search term is evaluated against text columns, lookup columns, choice columns, and numeric columns simultaneously. Typing 100 in a grid that has both a name column and an amount column will match records whose name starts with 100or whose amount equals 100. The search filter is layered on top of the view's existing filter, so view-level constraints (such as a statecode = 0 filter) are always preserved.
Disabling Search
Set AllowSearch="false" on the grid to hide the search box entirely. This is useful for grids that contain only a small fixed set of records, or where filtering is handled externally (for example via a custom toolbar).
The grid supports two paging strategies via the PagingMode parameter (Blazor) / pagingMode prop (React). Both modes use the same underlying view, FetchXML, sorting, and search — only the way rows are revealed to the user differs.
Paged (default) — a classic Prev / Next footer with a page-size selector. Best for shorter result sets and for cases where the user wants to jump around by page number or share a deep-linked page in the URL.
Virtualize — infinite scroll. The pager footer is hidden, rows accumulate as the user scrolls past the rendered bottom, and the next page fetches automatically. A read-only "Showing 1-N of M" counter replaces the pager once a total is available. Best for long lists where the user scans rather than navigates by page.
The same contact grid as the main demo, but with PagingMode="GridPagingMode.Virtualize" (Blazor) / pagingMode={PagingMode.Virtualize} (React) and a smaller chunk size so scrolling exercises the accumulator. The pager footer is gone — scroll down to pull in additional pages, and watch the counter at the top of the grid update as more rows stream in.
React example
Blazor example
Anyone can view contacts in the grid below. Log in to create, view, and update your own contacts.
All ContactsMy Contacts
All ContactsMy Contacts
Page size
102050100
Full Name
Mobile Phone
Email
Company Name
Age
React TypeScript
Razor
Tradeoffs
No jump-to-page. Virtualize mode always starts at the first page and pulls forward; consumers can no longer skip to page N. If you need explicit page navigation, stay on Paged.
Page is not persisted. Since the user's scroll position isn't a discrete page concept, PersistedStateQueryParameter omits the p key in virtualize mode. Selected view, sort, and (opt-in) search still round-trip through the URL.
Search and sort still work, but they reset the scrolled-in accumulator — changing the active view, applying a new sort, or typing in the search box drops the loaded rows and re-fetches from the top.
Hides the pager / page-size selector. The page-size selector is replaced by a fixed chunk size; set the initial value via DefaultItemsPerPage (Blazor) / pageSize (React) to control how many rows are fetched per scroll-triggered page.
Full Size Mode
Set FullSize="true" to make the grid expand to fill the full height of its parent container. This is useful when the grid is the main content of a page.
Set PersistedStateQueryParameter to a query-parameter name (e.g. "gridState") and the grid will mirror its interactive state into a single URL parameter under that name. Every user-driven change — switching the selected view, paging, resizing the page size, clicking column headers to sort, or (opt-in) typing in the search box — re-encodes the state and replaces the URL parameter in place. When the page is opened with the parameter present (bookmark, shared link, refresh), the grid reads the parameter on first load and restores all of the captured state before fetching data.
The query parameter encodes a compact JSON object with one short key per piece of state. Keys are deliberately abbreviated to keep bookmarked URLs short. Fields that match their natural defaults are omitted, so a grid sitting at page 1 with no sort and no search produces a much smaller blob than one with all five fields populated.
v — the selected view's GUID (lowercase, hyphenated, no braces). Matches one of the ViewIds / CustomViewDefinitions entries the grid was configured with.
p — the 1-based page number. Omitted when the user is on page 1 (the default).
ps — the number of rows per page. Reflects the user's last selection in the page-size dropdown; omitted when it matches the grid's DefaultItemsPerPage.
s — an ordered array of sort directives. Each entry has c (column logical name) and an optional d (set to true for descending; ascending is the unmarked default, so d is omitted in that case). Empty / unsorted state omits the field entirely. Multi-column sort is preserved in precedence order.
q — the current search-box text. Only included when the grid was configured with IncludeSearchInPersistedState="true" AND the box has a non-empty value. Off by default since search terms can be sensitive (e.g. customer names in a CRM context).
URL Encoding
The state is serialized as compact JSON (no whitespace) and URL-encoded into the query parameter. A grid showing page 3 of a contact view, sorted by lastname ascending then createdon descending, with search "smith" enabled would round-trip the following payload:
The encoder strips any field that matches its natural default before serializing. Page 1 drops p, an empty sort list drops s, an unmarked-ascending sort drops d, and an empty search drops q. A freshly-loaded grid with no user interaction encodes to a blob containing only v and ps — keeping bookmarked URLs from growing for state the consumer hasn't touched.
Browser History Behavior
State changes update the URL with history.replaceState — they don't push new entries onto the back stack. This means hitting Back from a grid page returns to the previous distinct page (the user's nav origin), not to the previous sort/page combination. The trade-off is intentional: a single grid session can produce dozens of state changes, and pushing each as a navigation entry would make the Back button effectively useless across the rest of the app.
Enabling Search Persistence
By default, search text is excluded from the URL so the parameter is safe to share even when the grid is filtering by a sensitive term. Set IncludeSearchInPersistedState="true" to include the current search box value in the encoded payload (added as the q field above). Once enabled, search becomes part of the bookmarkable state — the user can copy the URL and the recipient lands on the same view, page, sort, AND filter combination.
The encoded JSON shape is identical between the Blazor and React grid implementations — same parameter name, same keys (v / p / ps / s / q), same value semantics. A link produced by one stack is consumable by the other, so an organization that runs both surfaces (e.g. a public-facing React portal alongside an internal Blazor admin app) can share grid URLs between them without any per-stack translation layer.
Multiple grids on one page
Two grids on the same page must use differentPersistedStateQueryParameter names. Each grid only reads and writes its own parameter, so reusing the same name would have both grids fighting over the same URL slot — last write wins and the other grid loses its state on every change. A typical convention is to name the parameter after the grid's role (e.g. contactsState + accountsState).
Multi-Table Grids
A MainGrid can display views from different tables by including view IDs from multiple tables in the ViewIds collection. When the user switches views, the grid automatically loads the correct table's data. Use the OnClick callback on navigation buttons to dynamically set the URL based on the selected view's table name.
React
<MainGrid
viewIds={viewIds}
customViewDefinitions={customViews}
defaultViewId={ALL_CONTACTS_VIEW_ID}
>
<GridButtons>
<NavigateNewRecordGridButton
url="/contacts/new"
onClick={(ctx) => {
switch (ctx.gridContext.selectedView?.tableName) {
case 'contact': ctx.url = '/contacts/new'; break;
case 'account': ctx.url = '/accounts/new'; break;
default: throw new Error('Unknown table');
}
}}
/>
<NavigateOpenRecordGridButton
urlFor={(record, ctx) => {
switch (ctx.selectedView?.tableName) {
case 'contact': return `/contacts/edit?id=${record.id}`;
case 'account': return `/accounts/edit?id=${record.id}`;
default: throw new Error('Unknown table');
}
}}
/>
</GridButtons>
</MainGrid>Blazor
When true, the user can change the number of items displayed per page.
AllowDownloadForFileColumns
bool
True
When true (the default), the grid renders a per-row download icon at the trailing edge of file and image column cells. Clicking it streams the file to the user's browser. Set to false to suppress the icon — for example on read-only audit grids where file export isn't allowed.
AllowEdit
bool
False
Should the option be available for the user to turn on inline editing for the grid.
AllowNavigateOnPrimaryNameClick
bool
True
When true (the default) and the grid has a registered 'edit' button (a GridButton with IsOpenRecordButton=true), the cell that renders the table's primary-name column becomes a hyperlink. Clicking it dispatches the same per-row invocation that a row double-click would — so a user can jump to the edit form (or the navigated edit URL, depending on the registered button) without first selecting the row. Set to false to suppress the hyperlink and render the primary-name cell as plain text. Has no effect when no edit button is registered.
AllowNavigateOnRowDoubleClick
bool
True
When true (the default) and the grid has a registered 'edit' button (a GridButton with IsOpenRecordButton=true), double-clicking a row invokes that button's OnClick for the row's record — opening the edit dialog or navigating to the edit URL, whichever the button does. Set to false to suppress the double-click handler. Has no effect when no edit button is registered.
AllowPreviewForFileColumns
bool
True
When true (the default), the grid renders a per-row 'eye' preview icon at the trailing edge of file and image column cells whose contents can be rendered inline (images, PDFs, plain text). Set to false to suppress the icon — for example on grids where the columns shouldn't double as a preview entry point.
AllowSearch
bool
True
Should the user be allowed to search the grid.
BorderVisible
bool
True
Controls whether a visible border is rendered around the grid.
Buttons
RenderFragment?
Optional render fragment used to define the button toolbar displayed above the grid.
Columns
RenderFragment?
Optional GridColumns fragment carrying consumer-declared GridColumn children. When supplied, the grid switches to replace mode: only the declared columns render (in declared order), the FetchXML projection is rewritten to match, and the underlying view's column list is ignored. null leaves the grid in its default behavior (auto-generate columns from the view's resolved column set).
CustomViewDefinitions
List<GridViewDefinition>?
Custom views to display in the dropdown.
DataSource
ViewDataSource?
Optional shared Data.ViewDataSource. When set, the grid reads its rows + total count from the datasource instead of issuing its own RetrieveRecordsAsync(System.String) call — the same datasource can drive a sibling <DataverseChart> or a second grid so they all paginate / filter / search together off one round-trip. Standalone usage (no GridBase.DataSource) keeps the existing internal-state machine — the grid composes FetchXML and fetches via IPowerPortalsProService directly. What the datasource does NOT own: per-grid UI state (selected rows, pending row creates / updates / deletes, column widths). Those stay grid-local — two grids sharing one datasource can still have independent selection and per-grid pending edits. When ViewDataSource.Highlight is set (e.g. via a chart slice click in cross-filter 'highlight' mode), rows whose value in the highlighted column doesn't match are visually muted via a CSS class; the row data + selection are unaffected (the soft cross-filter is purely styling).
DefaultItemsPerPage
int
50
Default number of records to load on a page.
DefaultViewId
Guid?
Id of the view that the grid should display upon initial load.
Editable
bool
False
Is inline editing turned on for the grid.
Filters
IReadOnlyList<GridFilterBase>?
Additional server-side filters AND-merged onto the resolved view's FetchXML before paging / sorting / searching kick in. Forwarded to Query.IFetchXmlQueryComposer's FetchXmlQueryOptions.Filters, so each entry is dispatched by runtime type (e.g. Models.RelationshipFilter AND-merges a relationship link-entity). Typical use: the LinkExistingRecordGridButton picker passes a Models.RelationshipFilter with RelationshipFilterMode.ExcludeExistingRecords so already- linked records are hidden from the M2M lookup dialog. Combines additively with SubGrid's own internal relationship filter (which is built into the FetchXML directly rather than going through the composer's Filters slot) — both end up in the same query.
FullSize
bool
False
When true, the grid expands to fill all available vertical space instead of using a fixed minimum height.
HidePaging
bool
False
Force the page size and paging components to be hidden. Only do this when the number of items is known and the page size is set to something greater than the item count.
IncludeSearchInPersistedState
bool
False
When true, the active search text is included in the persisted state URL parameter (under the q field). Defaults to false — search terms can be sensitive, accumulate in browser history, and leak into HTTP referrers, so the grid keeps them out of the URL unless the consumer explicitly opts in. Has no effect when GridBase.PersistedStateQueryParameter is not set.
IsDirty
bool
False
Indicates whether the grid has unsaved create, update, or delete operations pending.
LoadedRecords
IEnumerable<TableRecord>
Records currently rendered in the grid (the most recent page of results). Intended for toolbar commands that need to act on 'everything shown' — e.g. a bulk download button. Does not span pages; bulk-across-pages operations should run their own unpaged fetch instead.
MaxHeight
string?
Max Height that the grid control should expand to.
MinHeight
string?
300px
Minimum height that the grid control should occupy.
Mode
GridMode
RecordSelection
Sets the behavioural mode of the grid, such as default interaction or record-selection mode.
PageSizes
IEnumerable<int>
Collection of available page sizes for the grid.
PagingMode
GridPagingMode
Paged
Determines whether the grid uses traditional paging or infinite-scroll virtualisation.
PersistedRowsSnapshot
PersistedGridRowsSnapshot?
Server-prerender → interactive handoff for the rendered page of rows. The framework auto-persists this property at the end of prerender and re-hydrates it before GridBase.OnInitializedAsync on the interactive side, so the data fetch can be skipped on first interactive render. Keyed by render-tree position by the framework; the PersistedGridRowsSnapshot.ViewId field is checked at consumption time so a rerender against a different view discards the stale rows. Public per the framework's requirement — [PersistentState] only sees public properties via reflection — but not intended to be set externally.
PersistedStateQueryParameter
string?
Name of the URL query-string parameter to persist the grid's interactive state to. When set, the grid reads this parameter on initial load and seeds the active view, page number, page size, and sort from it; subsequent user actions (view pick, page change, header sort, etc.) write the new state back via Components.NavigationManager's replace-state path. Persistence survives page refresh and bookmarks.
SelectedRecords
IEnumerable<TableRecord>
Records that are currently selected in the Grid.
SelectFromEntireRow
bool
True
When true, clicking anywhere on a row selects it; when false, only the checkbox selects the row.
SelectMode
DataGridSelectMode
Multiple
Controls whether the grid allows single or multiple row selection.
TableName
string?
The logical name of the table whose public views should be loaded. Only applicable when no values are specified for GridBase.DefaultViewId or GridBase.ViewIds.
Title
string?
Name to display when the view dropdown is not displayed.
Optional callback that runs immediately after a view is loaded and before the grid uses it to build columns or queries. Return a modified Models.GridViewDefinition to transform what the grid ultimately renders — for example, to ensure a specific column is always present regardless of the view's own configuration. Async so callers can consult metadata caches, services, or other async resources while deciding what to include.
ViewIds
IEnumerable<Guid>?
List of id's of the views that the grid should limit to in the view dropdown.
ViewSort
ViewSort
NameAscending
Sort order of the views in the view dropdown.
Name:AllowChangingPageSize
Type:bool
Default:True
Description:When true, the user can change the number of items displayed per page.
Name:AllowDownloadForFileColumns
Type:bool
Default:True
Description:When true (the default), the grid renders a per-row download icon at the trailing edge of file and image column cells. Clicking it streams the file to the user's browser. Set to false to suppress the icon — for example on read-only audit grids where file export isn't allowed.
Name:AllowEdit
Type:bool
Default:False
Description:Should the option be available for the user to turn on inline editing for the grid.
Name:AllowNavigateOnPrimaryNameClick
Type:bool
Default:True
Description:When true (the default) and the grid has a registered 'edit' button (a GridButton with IsOpenRecordButton=true), the cell that renders the table's primary-name column becomes a hyperlink. Clicking it dispatches the same per-row invocation that a row double-click would — so a user can jump to the edit form (or the navigated edit URL, depending on the registered button) without first selecting the row. Set to false to suppress the hyperlink and render the primary-name cell as plain text. Has no effect when no edit button is registered.
Name:AllowNavigateOnRowDoubleClick
Type:bool
Default:True
Description:When true (the default) and the grid has a registered 'edit' button (a GridButton with IsOpenRecordButton=true), double-clicking a row invokes that button's OnClick for the row's record — opening the edit dialog or navigating to the edit URL, whichever the button does. Set to false to suppress the double-click handler. Has no effect when no edit button is registered.
Name:AllowPreviewForFileColumns
Type:bool
Default:True
Description:When true (the default), the grid renders a per-row 'eye' preview icon at the trailing edge of file and image column cells whose contents can be rendered inline (images, PDFs, plain text). Set to false to suppress the icon — for example on grids where the columns shouldn't double as a preview entry point.
Name:AllowSearch
Type:bool
Default:True
Description:Should the user be allowed to search the grid.
Name:BorderVisible
Type:bool
Default:True
Description:Controls whether a visible border is rendered around the grid.
Name:Buttons
Type:RenderFragment?
Description:Optional render fragment used to define the button toolbar displayed above the grid.
Name:Columns
Type:RenderFragment?
Description:Optional GridColumns fragment carrying consumer-declared GridColumn children. When supplied, the grid switches to replace mode: only the declared columns render (in declared order), the FetchXML projection is rewritten to match, and the underlying view's column list is ignored. null leaves the grid in its default behavior (auto-generate columns from the view's resolved column set).
Name:CustomViewDefinitions
Type:List<GridViewDefinition>?
Description:Custom views to display in the dropdown.
Name:DataSource
Type:ViewDataSource?
Description:Optional shared Data.ViewDataSource. When set, the grid reads its rows + total count from the datasource instead of issuing its own RetrieveRecordsAsync(System.String) call — the same datasource can drive a sibling <DataverseChart> or a second grid so they all paginate / filter / search together off one round-trip. Standalone usage (no GridBase.DataSource) keeps the existing internal-state machine — the grid composes FetchXML and fetches via IPowerPortalsProService directly. What the datasource does NOT own: per-grid UI state (selected rows, pending row creates / updates / deletes, column widths). Those stay grid-local — two grids sharing one datasource can still have independent selection and per-grid pending edits. When ViewDataSource.Highlight is set (e.g. via a chart slice click in cross-filter 'highlight' mode), rows whose value in the highlighted column doesn't match are visually muted via a CSS class; the row data + selection are unaffected (the soft cross-filter is purely styling).
Name:DefaultItemsPerPage
Type:int
Default:50
Description:Default number of records to load on a page.
Name:DefaultViewId
Type:Guid?
Description:Id of the view that the grid should display upon initial load.
Name:Editable
Type:bool
Default:False
Description:Is inline editing turned on for the grid.
Name:Filters
Type:IReadOnlyList<GridFilterBase>?
Description:Additional server-side filters AND-merged onto the resolved view's FetchXML before paging / sorting / searching kick in. Forwarded to Query.IFetchXmlQueryComposer's FetchXmlQueryOptions.Filters, so each entry is dispatched by runtime type (e.g. Models.RelationshipFilter AND-merges a relationship link-entity). Typical use: the LinkExistingRecordGridButton picker passes a Models.RelationshipFilter with RelationshipFilterMode.ExcludeExistingRecords so already- linked records are hidden from the M2M lookup dialog. Combines additively with SubGrid's own internal relationship filter (which is built into the FetchXML directly rather than going through the composer's Filters slot) — both end up in the same query.
Name:FullSize
Type:bool
Default:False
Description:When true, the grid expands to fill all available vertical space instead of using a fixed minimum height.
Name:HidePaging
Type:bool
Default:False
Description:Force the page size and paging components to be hidden. Only do this when the number of items is known and the page size is set to something greater than the item count.
Name:IncludeSearchInPersistedState
Type:bool
Default:False
Description:When true, the active search text is included in the persisted state URL parameter (under the q field). Defaults to false — search terms can be sensitive, accumulate in browser history, and leak into HTTP referrers, so the grid keeps them out of the URL unless the consumer explicitly opts in. Has no effect when GridBase.PersistedStateQueryParameter is not set.
Name:IsDirty
Type:bool
Default:False
Description:Indicates whether the grid has unsaved create, update, or delete operations pending.
Name:LoadedRecords
Type:IEnumerable<TableRecord>
Description:Records currently rendered in the grid (the most recent page of results). Intended for toolbar commands that need to act on 'everything shown' — e.g. a bulk download button. Does not span pages; bulk-across-pages operations should run their own unpaged fetch instead.
Name:MaxHeight
Type:string?
Description:Max Height that the grid control should expand to.
Name:MinHeight
Type:string?
Default:300px
Description:Minimum height that the grid control should occupy.
Name:Mode
Type:GridMode
Default:RecordSelection
Description:Sets the behavioural mode of the grid, such as default interaction or record-selection mode.
Name:PageSizes
Type:IEnumerable<int>
Description:Collection of available page sizes for the grid.
Name:PagingMode
Type:GridPagingMode
Default:Paged
Description:Determines whether the grid uses traditional paging or infinite-scroll virtualisation.
Name:PersistedRowsSnapshot
Type:PersistedGridRowsSnapshot?
Description:Server-prerender → interactive handoff for the rendered page of rows. The framework auto-persists this property at the end of prerender and re-hydrates it before GridBase.OnInitializedAsync on the interactive side, so the data fetch can be skipped on first interactive render. Keyed by render-tree position by the framework; the PersistedGridRowsSnapshot.ViewId field is checked at consumption time so a rerender against a different view discards the stale rows. Public per the framework's requirement — [PersistentState] only sees public properties via reflection — but not intended to be set externally.
Name:PersistedStateQueryParameter
Type:string?
Description:Name of the URL query-string parameter to persist the grid's interactive state to. When set, the grid reads this parameter on initial load and seeds the active view, page number, page size, and sort from it; subsequent user actions (view pick, page change, header sort, etc.) write the new state back via Components.NavigationManager's replace-state path. Persistence survives page refresh and bookmarks.
Name:SelectedRecords
Type:IEnumerable<TableRecord>
Description:Records that are currently selected in the Grid.
Name:SelectFromEntireRow
Type:bool
Default:True
Description:When true, clicking anywhere on a row selects it; when false, only the checkbox selects the row.
Name:SelectMode
Type:DataGridSelectMode
Default:Multiple
Description:Controls whether the grid allows single or multiple row selection.
Name:TableName
Type:string?
Description:The logical name of the table whose public views should be loaded. Only applicable when no values are specified for GridBase.DefaultViewId or GridBase.ViewIds.
Name:Title
Type:string?
Description:Name to display when the view dropdown is not displayed.
Description:Optional callback that runs immediately after a view is loaded and before the grid uses it to build columns or queries. Return a modified Models.GridViewDefinition to transform what the grid ultimately renders — for example, to ensure a specific column is always present regardless of the view's own configuration. Async so callers can consult metadata caches, services, or other async resources while deciding what to include.
Name:ViewIds
Type:IEnumerable<Guid>?
Description:List of id's of the views that the grid should limit to in the view dropdown.
Name:ViewSort
Type:ViewSort
Default:NameAscending
Description:Sort order of the views in the view dropdown.
Events
Name
Type
Description
EditableChanged
EventCallback<bool>
Callback invoked when the inline editing state changes.
SelectedRecordsChanged
EventCallback<IEnumerable<TableRecord>>
Callback invoked when the selected records collection changes.
Name:EditableChanged
Type:EventCallback<bool>
Description:Callback invoked when the inline editing state changes.
Name:SelectedRecordsChanged
Type:EventCallback<IEnumerable<TableRecord>>
Description:Callback invoked when the selected records collection changes.
Methods
Name
Parameters
Type
Description
ClearSelectionAsync
Task
Clears all currently selected rows.
OpenFileDownloadAsync
TableRecord record string columnName
Task
Fetches the file/image column's bytes for record and streams them to the user's browser as a download. Invoked by the per-row download icon in file and image cells.
OpenFilePreviewAsync
TableRecord record string columnName
Task
Opens the inline preview dialog for the file/image column columnName on record. Invoked by the per-row preview icon in file/image cells and also available to composing components (for example, a toolbar button on a wrapping grid) that want a programmatic entry point.
RefreshAsync
bool forceRefresh
Task
Instructs the grid to re-fetch and render the current data from the supplied data source.
Validate
bool
Validates all editable rows in the grid.
Name:ClearSelectionAsync
Type:Task
Description:Clears all currently selected rows.
Name:OpenFileDownloadAsync
Parameters:TableRecord record string columnName
Type:Task
Description:Fetches the file/image column's bytes for record and streams them to the user's browser as a download. Invoked by the per-row download icon in file and image cells.
Name:OpenFilePreviewAsync
Parameters:TableRecord record string columnName
Type:Task
Description:Opens the inline preview dialog for the file/image column columnName on record. Invoked by the per-row preview icon in file/image cells and also available to composing components (for example, a toolbar button on a wrapping grid) that want a programmatic entry point.
Name:RefreshAsync
Parameters:bool forceRefresh
Type:Task
Description:Instructs the grid to re-fetch and render the current data from the supplied data source.
Name:Validate
Type:bool
Description:Validates all editable rows in the grid.
GridViewDefinition Class
Properties
Name
Type
Default
Description
Columns
List<ViewColumn>
The columns displayed in the grid, including their logical names and pixel widths.
DisplayName
string?
Optional display name for this view. When set, this is used as the default label in the view selector dropdown. A localization entry at tables.{TableName}.views.{Id}.label takes precedence if it exists.
FetchXml
string
The FetchXML query that defines which records and columns are retrieved for this view.
TableName
string
The logical name of the Dataverse table this view queries.
Name:Columns
Type:List<ViewColumn>
Description:The columns displayed in the grid, including their logical names and pixel widths.
Name:DisplayName
Type:string?
Description:Optional display name for this view. When set, this is used as the default label in the view selector dropdown. A localization entry at tables.{TableName}.views.{Id}.label takes precedence if it exists.
Name:FetchXml
Type:string
Description:The FetchXML query that defines which records and columns are retrieved for this view.
Name:TableName
Type:string
Description:The logical name of the Dataverse table this view queries.
Default RecordSelection
Paged Virtualize
Single SingleSticky Multiple
Default NameAscending NameDescending
Apply begins with filter on the following columns:
Company Name Email Full Name Mobile Phone
Apply begins with filter on the following columns:
Company Name Email Full Name Mobile Phone
Apply begins with filter on the following columns:
Company Name Email Full Name Mobile Phone
Uses number comparisons on the following columns:
Age
Apply begins with filter on the following columns: