Power Apps UI Design Patterns: Building Apps That Users Actually Enjoy Using
Introduction
Most Power Apps look like they were built by someone who has never used a modern app. Gray backgrounds, misaligned controls, tiny text, no loading indicators, and error messages that say "An error occurred." This is not because Power Apps cannot look good — it is because most makers do not know the design patterns that make apps professional and usable.
This guide covers the UI patterns that transform Power Apps from "functional but ugly" to apps that users actually enjoy opening. Based on Fluent UI principles, responsive design, and real-world user testing across enterprise deployments.
The Fluent UI Design System for Power Apps
Microsoft's Fluent UI provides the design language — use it consistently:
// Power Fx: Fluent UI color and typography system
// Define these on App.OnStart for consistent theming
Set(varTheme, {
// Primary brand colors (Fluent UI Blue)
Primary: ColorValue("#0078D4"),
PrimaryDark: ColorValue("#106EBE"),
PrimaryLight: ColorValue("#DEECF9"),
// Semantic colors
Success: ColorValue("#107C10"),
Warning: ColorValue("#FFB900"),
Error: ColorValue("#D13438"),
Info: ColorValue("#0078D4"),
// Neutral palette
Background: ColorValue("#FAFAFA"),
Surface: ColorValue("#FFFFFF"),
SurfaceHover: ColorValue("#F3F2F1"),
Border: ColorValue("#EDEBE9"),
BorderStrong: ColorValue("#C8C6C4"),
// Text colors
TextPrimary: ColorValue("#323130"),
TextSecondary: ColorValue("#605E5C"),
TextDisabled: ColorValue("#A19F9D"),
TextOnPrimary: ColorValue("#FFFFFF"),
// Typography
FontFamily: "Segoe UI",
FontSizeSmall: 12,
FontSizeBody: 14,
FontSizeSubtitle: 16,
FontSizeTitle: 20,
FontSizeHeader: 28,
FontSizeHero: 42,
// Spacing (8px grid)
SpacingXS: 4,
SpacingS: 8,
SpacingM: 16,
SpacingL: 24,
SpacingXL: 32,
SpacingXXL: 48,
// Elevation (shadows)
Shadow4: DropShadow.Regular,
Shadow8: DropShadow.Bold,
// Border radius
RadiusSmall: 4,
RadiusMedium: 8,
RadiusLarge: 12
});
Navigation Patterns
Pattern 1: Left Navigation (Desktop)
// Power Fx: Collapsible left navigation with icons
// Professional sidebar navigation for desktop apps
Set(varNavExpanded, true);
Set(varNavWidth, If(varNavExpanded, 240, 48));
// Navigation items
ClearCollect(
colNavItems,
{Icon: Icon.Home, Label: "Dashboard", Screen: scrDashboard, Badge: 0},
{Icon: Icon.People, Label: "Customers", Screen: scrCustomers, Badge: 0},
{Icon: Icon.DocumentBulletList, Label: "Orders", Screen: scrOrders, Badge: 3},
{Icon: Icon.Settings, Label: "Reports", Screen: scrReports, Badge: 0},
{Icon: Icon.Lock, Label: "Admin", Screen: scrAdmin, Badge: 1}
);
// Active item tracking
Set(varActiveNavItem, "Dashboard");
// Navigation item OnSelect
Navigate(ThisItem.Screen, ScreenTransition.None);
Set(varActiveNavItem, ThisItem.Label);
Pattern 2: Bottom Tab Bar (Mobile)
// Power Fx: Bottom tab navigation for mobile apps
// 4-5 tabs maximum, always visible
// Tab bar layout
Set(varTabBarHeight, 56);
Set(varTabWidth, App.Width / 4);
// Tab items
ClearCollect(
colTabItems,
{Icon: Icon.Home, Label: "Home", Screen: scrHome, Active: true},
{Icon: Icon.Search, Label: "Search", Screen: scrSearch, Active: false},
{Icon: Icon.Add, Label: "New", Screen: scrCreate, Active: false},
{Icon: Icon.Person, Label: "Profile", Screen: scrProfile, Active: false}
);
Responsive Layout Patterns
// Power Fx: Responsive breakpoint system
// Adapts layout based on device width
Set(
varLayout,
If(
App.Width >= 1200,
{
Mode: "Desktop",
Columns: 3,
SidebarVisible: true,
CardWidth: (App.Width - 320 - 64) / 3,
FontScale: 1
},
App.Width >= 768,
{
Mode: "Tablet",
Columns: 2,
SidebarVisible: false,
CardWidth: (App.Width - 48) / 2,
FontScale: 0.95
},
{
Mode: "Mobile",
Columns: 1,
SidebarVisible: false,
CardWidth: App.Width - 32,
FontScale: 0.9
}
)
);
// Use in control properties:
// Gallery template size: varLayout.CardWidth
// Sidebar visibility: varLayout.SidebarVisible
// Font size: varTheme.FontSizeBody * varLayout.FontScale
Loading State Patterns
Users need to know something is happening. Never leave them staring at a blank screen:
// Power Fx: Loading state management
// Show skeleton screens, spinners, and progress indicators
// State machine for data loading
Set(varLoadingState, "loading"); // "loading" | "success" | "error" | "empty"
// On data load start
Set(varLoadingState, "loading");
Set(varLoadingMessage, "Loading your dashboard...");
// After data loads
ClearCollect(colData, Filter(DataSource, Active = true));
Set(
varLoadingState,
If(
CountRows(colData) > 0,
"success",
"empty"
)
);
// UI conditional rendering (set on control Visible properties):
// Skeleton/Spinner: varLoadingState = "loading"
// Data gallery: varLoadingState = "success"
// Empty state: varLoadingState = "empty"
// Error banner: varLoadingState = "error"
Empty State Design
// Power Fx: Friendly empty state instead of blank screen
// Show when a gallery has no items
// Empty state properties
Set(varEmptyState, {
Icon: Icon.DocumentBulletList,
Title: "No tasks yet",
Subtitle: "Create your first task to get started",
ActionLabel: "Create Task",
ActionScreen: scrCreateTask
});
// Visible when gallery is empty
// Visibility: CountRows(colTasks) = 0 && varLoadingState <> "loading"
Form Design Patterns
Smart Form with Progressive Disclosure
// Power Fx: Progressive disclosure form
// Show fields progressively based on previous selections
// Section visibility control
Set(varFormSection, 1);
// Section 1: Basic Info (always visible)
// Section 2: Details (visible after section 1 complete)
Set(
varSection2Visible,
!IsBlank(txtName.Text)
&& !IsBlank(drpCategory.Selected)
&& Len(txtName.Text) >= 3
);
// Section 3: Review (visible after section 2 complete)
Set(
varSection3Visible,
varSection2Visible
&& !IsBlank(txtDescription.Text)
&& Len(txtDescription.Text) >= 20
);
// Form completion progress
Set(
varFormProgress,
(
CountIf(
Table(
{Complete: !IsBlank(txtName.Text)},
{Complete: !IsBlank(drpCategory.Selected)},
{Complete: !IsBlank(txtDescription.Text)},
{Complete: !IsBlank(drpPriority.Selected)},
{Complete: !IsBlank(dpkDueDate.SelectedDate)}
),
Complete = true
) / 5
) * 100
);
Inline Validation
// Power Fx: Real-time field validation with visual feedback
// Show validation errors as user types
// Email validation
Set(
varEmailValid,
IsMatch(
txtEmail.Text,
Match.Email
)
);
Set(
varEmailError,
If(
IsBlank(txtEmail.Text), "",
!varEmailValid, "Please enter a valid email address",
""
)
);
// Email field border color
// Normal: varTheme.Border
// Error: varTheme.Error
// Valid: varTheme.Success
// Formula: If(!IsBlank(varEmailError), varTheme.Error, varEmailValid, varTheme.Success, varTheme.Border)
Card Design Pattern
{
"card_design_system": {
"card_anatomy": {
"container": {
"background": "Surface (#FFFFFF)",
"border": "1px solid Border (#EDEBE9)",
"border_radius": "8px",
"padding": "16px",
"shadow": "0 2px 4px rgba(0,0,0,0.04)"
},
"header": {
"layout": "Icon + Title + Status Badge",
"title_font": "Segoe UI Semibold, 16px, TextPrimary",
"subtitle_font": "Segoe UI, 12px, TextSecondary"
},
"body": {
"layout": "Key-value pairs or compact data",
"font": "Segoe UI, 14px, TextPrimary"
},
"footer": {
"layout": "Action buttons (right-aligned) or metadata",
"separator": "1px solid Border above footer"
}
},
"card_variants": [
"Standard (white bg, gray border)",
"Elevated (stronger shadow, no border)",
"Colored top (4px colored top border for status)",
"Selected (Primary border, light Primary bg)"
]
}
}
Accessibility Checklist
| Requirement | WCAG Level | Power Apps Implementation |
|---|---|---|
| Color contrast 4.5:1 | AA | Use TextPrimary (#323130) on white — ratio 14.5:1 |
| Keyboard navigation | AA | Set TabIndex on all interactive controls |
| Screen reader labels | AA | Set AccessibleLabel on every control |
| Touch target 44x44px | AA | Minimum button size: 44px height |
| Focus indicators | AA | Use FocusedBorderColor property |
| Alt text for images | AA | Set AccessibleLabel on Image controls |
| Error identification | AA | Associate error messages with form fields |
| No color-only indicators | AA | Add icons alongside status colors |
// Power Fx: Accessible status indicator
// Never use color alone to convey meaning
// ❌ Color only
Set(varStatusColor, If(Status = "Active", Color.Green, Color.Red));
// ✅ Color + Icon + Text (accessible)
Set(varStatusDisplay, {
Color: If(Status = "Active", varTheme.Success, varTheme.Error),
Icon: If(Status = "Active", Icon.Check, Icon.Cancel),
Text: If(Status = "Active", "Active", "Inactive"),
AriaLabel: "Status: " & If(Status = "Active", "Active", "Inactive")
});
Architecture Decision and Tradeoffs
When designing low-code development solutions with Power Apps, consider these key architectural trade-offs:
| Approach | Best For | Tradeoff |
|---|---|---|
| Managed / platform service | Rapid delivery, reduced ops burden | Less customisation, potential vendor lock-in |
| Custom / self-hosted | Full control, advanced tuning | Higher operational overhead and cost |
Recommendation: Start with the managed approach for most workloads and move to custom only when specific requirements demand it.
Validation and Versioning
- Last validated: April 2026
- Validate examples against your tenant, region, and SKU constraints before production rollout.
- Keep module, CLI, and SDK versions pinned in automation pipelines and review quarterly.
Security and Governance Considerations
- Apply least-privilege access using RBAC roles and just-in-time elevation for admin tasks.
- Store secrets in managed secret stores and avoid embedding credentials in scripts or source files.
- Enable audit logging, data protection policies, and periodic access reviews for regulated workloads.
Cost and Performance Notes
- Define budgets and alerts, then monitor usage and cost trends continuously after go-live.
- Baseline performance with synthetic and real-user checks before and after major changes.
- Scale resources with measured thresholds and revisit sizing after usage pattern changes.
Official Microsoft References
- https://learn.microsoft.com/power-apps/
- https://learn.microsoft.com/power-platform/admin/
- https://learn.microsoft.com/power-platform/guidance/
Public Examples from Official Sources
- These examples are sourced from official public Microsoft documentation and sample repositories.
- Documentation examples: https://learn.microsoft.com/power-apps/
- Sample repositories: https://github.com/microsoft/PowerApps-Samples
- Prefer adapting these examples to your tenant, subscriptions, and governance requirements before production use.
Key Takeaways
- Define a theme system on App.OnStart — colors, fonts, spacing — and reference it consistently across all controls
- Choose navigation patterns based on device: left sidebar for desktop, bottom tabs for mobile, hamburger menu for tablet
- Always show loading states — skeleton screens or spinners prevent users from thinking the app is broken
- Design friendly empty states — a blank gallery with "No data" is bad UX; an illustration with a call-to-action is good UX
- Progressive disclosure reduces form overwhelm — show fields as they become relevant, not all at once
- Inline validation provides immediate feedback — users should never submit a form to discover errors
- Accessibility is not optional — color contrast, keyboard navigation, screen reader labels, and touch targets affect real users
- Fluent UI is your design system — follow Microsoft's patterns for professional, consistent, and accessible apps
Discussion