Home / PowerApps / Power Apps UI Design Patterns: Building Apps That Users Actually Enjoy Using
PowerApps

Power Apps UI Design Patterns: Building Apps That Users Actually Enjoy Using

UI design patterns for Power Apps that go beyond functional to delightful — covering Fluent UI principles, responsive layouts, navigation patterns, loading states, error handling UX, and accessibility compliance.

What you will learn

Practical execution with concise explanations, real implementation patterns, and production-ready recommendations.

Power Apps UI Design Patterns: Building Apps That Users Actually Enjoy Using

Introduction

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

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

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

Additional Resources

Discussion