Views are the primary lens users interact with in model-driven apps — and most of them are badly designed. Learn how to build purpose-built views with multi-condition filters, strategic sort orders, FetchXML for complex queries, and editable grids for inline record editing.

Picture this: your sales team's model-driven app has a single "Active Accounts" view showing every account in the system — all 4,200 of them — sorted alphabetically by account name. Every morning, reps scroll endlessly looking for their assigned accounts in the Pacific Northwest region, past hundreds of records they'll never touch. Meanwhile, the operations manager is asking why the app feels slow and why her team keeps making data entry errors when updating renewal dates one record at a time.
Views are the primary lens through which users interact with data in a model-driven app. They're not just filters on a list — they're the difference between a tool that helps people work efficiently and one that generates daily frustration. A well-designed view surfaces exactly the right records in the right order, with the right columns visible, scoped to exactly what a given user needs to see. A poorly designed view dumps everything in the user's lap and calls it a day.
By the end of this lesson, you'll be able to build views that do real work: filtered down to meaningful subsets of data, sorted strategically, and enabled for direct inline editing through editable grids — so your users can update records without ever leaving the list.
What you'll learn:
This lesson assumes you're comfortable with Dataverse fundamentals — specifically that you understand tables, columns, and rows in Dataverse and that you've already worked through building a basic model-driven app including the basics of forms and views. You should also have a working Dataverse environment with at least one table that has meaningful data or a realistic schema. The examples throughout this lesson use a Service Request scenario with related Account and Technician tables, but the patterns apply universally.
Before you open the view designer, you need to understand that not all views are the same kind of object. Model-driven apps have several distinct view types, each with a specific role, and using the wrong type for the job creates problems down the road.
Public views (sometimes called System views) are the workhorses. They're visible to all users who have access to the table and appear in the view selector dropdown on list pages. When you create a new view in the designer and publish it, this is what you get by default. Your regional filters and role-based record sets should live here.
Default views are a subset of public views. Every table has one designated default view — the one that loads when a user navigates to that table's list page for the first time. Choosing the right default view matters enormously for first-run experience. The system-generated "Active [Table Name]" view is the default out of the box, but you should almost always replace it with something more contextually appropriate.
Quick Find views control what happens when a user types in the search box at the top of a list. Only one Quick Find view exists per table, and it defines both which columns are searched and which columns appear in the results popup. Getting this right dramatically improves your app's usability.
Lookup views control what records and columns appear when a user opens a lookup field popup — for example, clicking the magnifying glass next to the "Account" field on a Service Request form. These are separate from your main list views and deserve their own attention.
Associated views appear in subgrids and related record lists — for example, the list of Service Requests you see at the bottom of an Account form. These typically show a narrower set of columns relevant to the context of the parent record.
Note
Personal views are created by individual users from within the app itself, using the "Create personal view" option in the view selector. They're not managed in the designer — users control them independently. As a maker, you can't delete someone's personal view, but your published system views always take precedence as the starting selection.
Open the Power Apps maker portal (make.powerapps.com), select your solution, then navigate to your table. Under the Views tab, you'll see all existing views for that table. Click New view or open an existing one.
The view designer gives you a canvas-style layout with two primary working areas: the column list on the left showing all available columns, and the column display area across the top representing what will actually appear in the grid. Below the column display area is the filter panel and the sort settings.
To add a column, either drag it from the left panel or click its name and select Add column. The order you add them determines the left-to-right order in the grid. You can reorder columns by dragging the column headers in the display area.
Column width matters more than most makers realize. The default width of 100px is too narrow for most text fields and too wide for most date or status fields. Click a column header in the display area and set an explicit width — 150px for short text, 200-250px for names and descriptions, 90px for dates and status fields. Users notice immediately when columns are badly sized.
Tip
Don't try to cram every potentially useful column into a single view. Views are about quick scanning, not exhaustive information. If users need to see more, they click the record and open the form. A view with 12 columns forces horizontal scrolling on any normal monitor and defeats the purpose of a list.
The columns available in the view designer include not just direct columns on the table, but also related columns from parent lookups. If your Service Request table has a lookup to Account, you can pull in the Account's Industry or Primary Contact directly into the view. These "related columns" are powerful but come with a performance cost we'll discuss in the sorting section.
Filters are where views go from "a list of records" to "the right records for this context." The view filter editor is a visual query builder — no code required for most scenarios — but you need to understand the underlying logic to use it well.
In the view designer, click Edit filters in the right panel. You'll see a condition group with an And/Or operator and a list of conditions. Each condition has three parts: a column, an operator, and a value.
For our Service Request scenario, a useful starting filter might be:
But here's a subtlety that trips up many makers: the And/Or at the top of the filter group applies to all conditions in that group. If you want "Status = Active AND (Region = Pacific Northwest OR Region = Mountain West)", you need nested groups — a parent AND group containing the Status condition and a nested OR group containing the two region conditions.
To create a nested group, click Add group inside the filter editor. This inserts a sub-group with its own And/Or operator. Drag conditions into it or add new conditions directly inside the group.
Here's what the logic looks like for a "My Region's Active Requests" view:
AND
├── Status = Active
└── OR
├── Region = Pacific Northwest
└── Region = Mountain West
The real power of view filters is dynamic values — conditions that evaluate at runtime based on the current user or the current date, rather than being hardcoded strings.
The most important dynamic value is [Current User] (sometimes shown as "Current User"). When you set a filter like "Assigned Technician equals [Current User]", each person who uses the view sees only their own assigned records. You don't need a separate view per person — one view adapts to everyone.
Other dynamic values available include:
For a service management app, combining these gives you high-signal views immediately:
Warning
"Null" checks behave differently depending on the column type. For lookup columns, use "Does not contain data" rather than "equals null." For choice/option set columns, "Does not contain data" also works, but be aware it catches records where the field was never populated — which may be different from records where the field was explicitly cleared.
The visual filter editor covers maybe 80% of real-world filtering needs. For the other 20% — complex date range comparisons, aggregate-based conditions, or filters involving many-to-many relationships — you need FetchXML.
FetchXML is the XML query language that Dataverse uses internally. Every view filter compiles to FetchXML under the hood. You can access and edit the raw FetchXML by downloading it from the view's advanced settings, editing it externally, then uploading it back.
A practical example: suppose you need a view of Service Requests where the SLA deadline is within 48 hours and the status is still Active. The visual editor can't express "within 48 hours of now" — that's a relative calculation. In FetchXML, you can use the olderThan / within operators:
<fetch>
<entity name="new_servicerequest">
<attribute name="new_requestnumber" />
<attribute name="new_title" />
<attribute name="new_status" />
<attribute name="new_sladeadline" />
<attribute name="new_assignedtechnicianid" />
<filter type="and">
<condition attribute="new_status"
operator="eq"
value="1" />
<condition attribute="new_sladeadline"
operator="next-x-hours"
value="48" />
</filter>
<order attribute="new_sladeadline" descending="false" />
</entity>
</fetch>
The next-x-hours operator evaluates dynamically at runtime — every time the view loads, it recalculates based on the current timestamp. No hardcoded dates, no manual maintenance.
To use FetchXML with a view, the most reliable workflow is:
SavedQuery XML file for your view<fetch> element directlyKey insight
The XrmToolBox tool "FetchXML Builder" (a free community tool) makes editing and testing FetchXML dramatically easier. You can write the query visually, test it against live data, then paste the resulting FetchXML into your solution XML. For any team doing serious model-driven development, this tool is non-negotiable.
Sorting in a view serves two purposes: it controls the default presentation order when the view first loads, and it hints to Dataverse how to optimize the query. Both matter for production systems with meaningful data volumes.
In the view designer, click a column header in the display area to sort by that column. A small arrow indicator shows the sort direction. Click again to reverse direction. To add a secondary sort, hold Shift while clicking a second column.
Alternatively, open the Sort panel (accessible from the command bar in the view designer) to set sort orders explicitly and manage priority. You'll see a numbered list where 1 is the primary sort, 2 is the secondary, and so on. Drag to reorder priority.
For our service management scenario, a well-considered multi-level sort might be:
This creates a meaningful automatic triage order where the most urgent work is always at the top.
Sorting on choice columns (option sets) sorts by the underlying numeric value, not the label alphabetically. This means you control the sort order by controlling the values you assigned when you designed the column. If you want Critical = highest priority, assign it value 100 (or whatever your highest number is), and sort descending.
If you inherited a schema where the values weren't designed with sort order in mind — say, Critical = 1, High = 2, Medium = 3, Low = 4 — then sorting ascending will actually give you the right order. The key is to verify this with real data before publishing.
Sorting on related columns (columns pulled in from a parent table via lookup) is significantly more expensive than sorting on direct columns. When you sort on "Account.Industry" in a Service Request view, Dataverse has to join the Account table in the query, and that join happens at query time for every page load. On tables with tens of thousands of records, this can cause noticeable delays.
The practical rule: sort on indexed columns on the primary table. Status, created on, modified on, owner, and the primary key are all indexed by default. Custom columns you create are not automatically indexed — you need to explicitly enable indexing in the column's settings if you plan to sort or filter on them heavily.
Tip
If you're pulling a related column into a view for display purposes (showing the Account's industry in the Service Request list), that's fine. But don't make that related column your primary sort. Add an equivalent direct column to the Service Request table — a "Cached Industry" field that gets populated via automation — if you need to sort on it frequently at scale.
Here's where views go from read-only lists to interactive data management surfaces. The Editable Grid control lets users update field values directly in the list — no need to open individual records, make a change, save, and navigate back to the list. For bulk updates to a common field (updating status on 20 records, adjusting renewal dates, reassigning ownership), it cuts the time required by an order of magnitude.
By default, model-driven app views display a read-only grid. The Editable Grid is a separate control that you configure at the table or view level. When enabled, users can:
The editable grid supports most column types: text, numbers, dates, choice columns, yes/no fields, lookups, and currency. It does not support calculated columns (they're read-only by nature), rollup columns, or file/image columns.
To enable the Editable Grid for a table in your model-driven app:
Alternatively, you can configure the Editable Grid at the individual view level rather than the table level, which gives you finer control. To do this:
The view-level configuration is more precise but requires per-view setup. The table-level approach applies the editable grid to all views on that table, which is simpler but less targeted.
Once you've added the Editable Grid control, you'll see a property panel with several important settings:
Enable Filtering — When set to Yes, users see an inline filter row at the top of each column where they can type to filter the visible records. This is separate from the view's built-in filter and operates on the client side (within the already-loaded records). For views with large datasets, remind users that client-side filtering only applies to loaded records, not the full dataset.
Enable Grouping — Allows users to drag a column header to a grouping zone, collapsing records by that column's value. Useful for summary-style views. Note that grouping disables multi-record editing.
Show Tooltip — Controls whether cell-level validation messages appear as tooltips on hover.
Enable Pre-Grid Filtering — When enabled, users see filter options before the grid loads, which can prevent unnecessary data loading for large tables. This is especially valuable for tables with millions of rows.
Grouped Controls — You can specify related records to show in nested rows — essentially an inline subgrid — but this is an advanced feature best approached after you're comfortable with the basic editable grid.
Here's a realistic configuration for a "Service Request Triage" view in a service management app — the configuration you'd set in the control properties:
Enable Filtering: Yes
Enable Grouping: No
Show Tooltip: Yes
Enable Pre-Grid Filtering: No
Form Factor: Web, Tablet
Grouping is disabled because the view already has meaningful sorting by priority and SLA deadline, and grouping would interfere with that ordering. Pre-grid filtering is off because this view is already heavily filtered by the view's own conditions and the dataset is manageable.
Warning
Enabling the Editable Grid changes the visual interaction model for users. If your users are accustomed to clicking a row to open the record form, they may be confused when a single click now selects the row for editing instead of navigating to the form. Plan for a short training communication when rolling this out. The full record form opens via the record's linked name column — usually the primary field — which remains a navigation link even in editable grid mode.
The crown jewel of the Editable Grid is multi-record editing. Here's how it works in practice:
This is genuinely powerful for scenarios like:
The underlying mechanism fires a separate update call per record — it's not a true bulk update in the database sense — so very large selections (hundreds of records) can be slow. For actual bulk database operations at scale, that's a job for Power Automate or a plugin. But for the 5-50 record range that a user would realistically select manually, it works well.
Key insight
Multi-record editing respects field-level security and business rules. If a column has field-level security restricting a user's write access, that column won't be editable for that user even in the editable grid. Business rules that fire on save will also execute per record, so if you have validation logic, it applies individually. This is actually a feature — your data integrity rules still hold.
Role-based security in model-driven apps determines which records users can see at the data layer. But views determine what they see at the interface layer. These two mechanisms work together.
A common pattern is creating role-optimized views that pair with security roles. Consider a service management app with three roles: Technician, Team Lead, and Operations Manager.
Technician views:
Team Lead views:
Operations Manager views:
Notice that none of these views require different security configurations — they're all public views visible to anyone with access to the table. The filtering is purely about presenting the right slice of data for each role's workflow. If security needs to restrict which records a role can access at all, that's configured in the security role definition, not in views.
Note
You can't programmatically set a different default view for different users or roles. The default view is a single system setting per table. If you need role-specific defaults, the standard workaround is to train each user group to set their preferred view as their personal default (available from the view selector dropdown → "Set as my default view"). Personal defaults persist per user and override the system default.
The Quick Find view deserves its own discussion because it controls one of the most frequently used features: the search box. When users type in the search bar on a list page, Dataverse runs a "starts with" query against specific columns defined in the Quick Find view.
Every table has exactly one Quick Find view. Open it from the Views list — it's labeled "Quick Find Active [Table Name]" by default.
The Quick Find view has a different structure from regular views. It has two distinct column sections:
Find Columns — The columns that are actually searched. When a user types "Smith", Dataverse checks all Find Columns for records starting with "Smith". Add the columns users are most likely to search by: request number, title, customer name, technician name.
View Columns — The columns that appear in the search results popup. Keep this to 3-4 highly identifying columns so the popup is scannable.
A common mistake is adding too many Find Columns, thinking it makes search more powerful. In practice, each additional Find Column adds a query condition joined with OR, which increases query cost. Stick to 4-6 genuinely useful search columns.
For the Service Request Quick Find view, a well-designed setup:
Find Columns:
View Columns:
This lets users search by any of those four fields and immediately see the key identifying information in the results.
Let's build a complete, production-ready view for a service management scenario. If you're following along with your own environment, substitute your actual table name and column names.
Scenario: You're building a "High Priority Escalation Queue" view for team leads in a field service organization. This view should show all active service requests that are high or critical priority, were created more than 24 hours ago, and are either unassigned or assigned to technicians who haven't updated them in the last 8 hours.
Step 1: Create the view
Step 2: Add and arrange columns Add these columns in order, with suggested widths:
Step 3: Build the filter
Create an AND group with:
Then add a nested OR group for:
The full logic reads: "Active + (High or Critical) + created over 24 hours ago + (unassigned OR not updated in 8 hours)."
Step 4: Set the sort
Step 5: Enable Editable Grid
Step 6: Test Save and publish. Open the app, navigate to Service Requests, and select your new view. Verify that:
This view gives team leads a self-updating escalation queue that requires zero manual sorting or filtering every morning. It's the kind of view that makes people thank you for building the app.
"My filter isn't showing the right records." First, check the And/Or logic. Most filter errors are due to incorrect group logic — an OR where you needed an AND, or conditions in the wrong group. The visual editor can be misleading; recreate the filter from scratch if you're unsure, adding conditions one at a time and testing after each addition.
"The view loads slowly." Check your sort columns. If you're sorting on a related column (from a lookup), switch to sorting on a direct column. Also check your filter — are you filtering on an unindexed custom column? Enable indexing on that column in the column settings, or restructure the filter to use an indexed column. Views with many related columns (pulling in 4+ joined table columns) are also slower — consider denormalizing by creating direct columns populated via Power Automate.
"The Editable Grid control doesn't appear, even though I added it." The Editable Grid control requires that the Read-Write form factor you selected matches the user's actual form factor. If you enabled it for Web only but a user is on a tablet browser, it won't appear. Also verify you've published the app after adding the control — unpublished changes don't reach users.
"Users can see the view but can't edit fields in the editable grid." This is almost always a security role issue. Check the user's security role for field-level security on the columns they're trying to edit, and confirm they have the Write privilege on the table. The editable grid doesn't grant permissions — it just exposes the editing interface for permissions you already have.
"My Quick Find search isn't returning results I expect." Quick Find uses "starts with" semantics, not "contains." If users search "Smith" they'll find "Smith Plumbing" but not "John Smith." This is by design for performance reasons. If you need contains-style search, enable Relevance Search (Dataverse Search) in your environment settings — it provides full-text search across all searchable tables and columns.
Warning
Be careful with views that have no filter conditions at all — essentially "show me every record in the table." On a table with 100,000+ rows, these views will hit performance limits and may load slowly or timeout. Always filter down to a meaningful working set. If someone genuinely needs to browse the entire dataset, that's a data analysis task — export to Excel or use Power BI, not a model-driven app view.
"I published a new view but users see the old one." Views are cached on the client. Ask users to do a hard refresh (Ctrl+Shift+R / Cmd+Shift+R) or clear their browser cache. In some cases, users need to sign out and back in. In enterprise environments with aggressive caching, it can take up to an hour for published changes to propagate to all users.
Views are the primary interface between your data and your users in a model-driven app. Done well, they reduce cognitive load, speed up common workflows, and make users feel like the app was built specifically for them. Done carelessly, they create noise and frustration that undermine the entire application.
Here's what you've built in this lesson:
The logical next area to explore from here is forms — specifically designing model-driven forms with sections, tabs, subgrids, and quick view forms, since views and forms are the two halves of a complete record interaction experience. When a user clicks through from your carefully designed view, the form they land on needs to be equally thoughtful.
You should also revisit your data model design with your new view knowledge in mind — specifically whether any columns need indexing enabled, whether denormalized "cached" fields would help view performance, and whether your choice column values are ordered in a way that sorts correctly.
Finally, if your organization has multiple security roles with meaningfully different data access needs, the interaction between security roles and what users see in views deserves dedicated attention — especially the difference between view-level filtering (presentation) and security-role filtering (data access enforcement).
Model-Driven Apps & Dataverse