Loading Screen
Full-screen branded splash screen with animated logo ring, indeterminate progress bar, step-by-step status messages, and dot indicators. Supports dark and light themes, custom accent color, configurable wordmark, and multi-stage loading feedback. Drop it on your first screen and hide it once OnStart finishes. 13 properties, 1 event.
- 1. Go to the Components tab (right side panel, next to Screens)
- 2. Click New component — this creates a blank component
- 3. Click outside the new component to deselect it
- 4. Paste the YAML with Ctrl+V / ⌘V
Preview
Installation
- Copy the YAML using the button above.
- Open your canvas app in Power Apps Studio.
- Go to Components → New component → Import from code.
- Paste the YAML and click Save.
- Insert
cmpLoadingScreenon your first screen and setWidth = App.Width,Height = App.Height. - Wire
OnReadytoSet(gAppReady, true)and setVisibleto!gAppReady. - Z-order: ensure the component is the last child on the screen in the tree (bottom of the layers panel). Power Apps renders later children on top — if other controls are above it the loading screen will appear behind your app UI.
Usage
Basic setup with OnStart + OnReady
// App.OnStart — run your init logic, advance CurrentStep
Set(gLoadStep, 1);
ClearCollect(colLaborRates, 'Labor Rates'); Set(gLoadStep, 2);
ClearCollect(colEquipRates, 'Equipment Rates'); Set(gLoadStep, 3);
ClearCollect(colProjects, Projects); Set(gLoadStep, 4);
// cmpLoadingScreen.CurrentStep = gLoadStep
// cmpLoadingScreen.OnReady = Set(gAppReady, true)
// cmpLoadingScreen.Visible = !gAppReadyCustom branding
cmpLoadingScreen.AppName = "Contoso"
cmpLoadingScreen.AppNameAccent = "Inventory"
cmpLoadingScreen.AppSubtitle = "Stock Management"
cmpLoadingScreen.LogoLetter = "C"
cmpLoadingScreen.CompanyName = "Contoso Ltd."
cmpLoadingScreen.AppVersion = "v1.0"
cmpLoadingScreen.AccentColor = RGBA(79, 142, 247, 1)
cmpLoadingScreen.Theme = "Dark"Custom loading steps
// Match each step to a real loading operation in OnStart
cmpLoadingScreen.LoadingSteps = Table(
{msg: "Authenticating user…" },
{msg: "Loading projects…" },
{msg: "Syncing rate tables…" },
{msg: "Almost ready…" }
)Enterprise auth check
// App.OnStart — check group membership before loading data
Set(gLoadStep, 1);
Set(gCurrentUser, LookUp('User Profiles', Email = User().Email));
// Verify user has access
If(
IsBlank(gCurrentUser) || gCurrentUser.Role = "None",
Set(gLoadError, "Access denied. Contact your administrator."),
// Proceed with normal loading
Set(gLoadStep, 2);
ClearCollect(colProjects, Projects); Set(gLoadStep, 3);
ClearCollect(colRates, RateTables); Set(gLoadStep, 4);
);
// cmpLoadingScreen.ErrorMessage = gLoadError
// cmpLoadingScreen.OnReady = Set(gAppReady, true)
// cmpLoadingScreen.Visible = !gAppReadyMinDisplayTime and OnReady
// OnReady fires once MinDisplayTime has elapsed.
// Wire it to set your ready flag — no need to poll IsReady manually.
// cmpLoadingScreen.MinDisplayTime = 1500 ← default (ms)
// cmpLoadingScreen.OnReady = Set(gAppReady, true)
// cmpLoadingScreen.Visible = !gAppReady
// If OnStart finishes before the timer, the screen stays visible
// until MinDisplayTime elapses, then OnReady fires and hides it.
// If OnStart takes longer, gAppReady stays false regardless — the
// Visible formula keeps the screen up until both conditions clear.Properties
Input
| Property | Type | Default |
|---|---|---|
AppNameFirst word of the wordmark in the default text color. | Text | "PowerApps" |
AppNameAccentSecond word of the wordmark rendered in AccentColor. Leave blank for single-word app names. | Text | "UI" |
AppSubtitleSmall uppercase subtitle below the wordmark. | Text | "Component Library" |
LogoLetterSingle character displayed inside the logo mark square. | Text | "P" |
CompanyNameLeft side of the version badge at the bottom of the screen. | Text | "powerappsui.com" |
AppVersionVersion string shown in the bottom badge after the company name. | Text | "v1.0" |
AccentColorAccent color applied to the logo, wordmark, divider, dots, progress bar, glows, and version label. The ring pulse uses a hardcoded default blue — Power Fx has no channel extraction functions to derive dynamic alpha from a Color value. | Color | RGBA(79,142,247,1) |
Theme"Dark" renders on a near-black background. "Light" renders on a soft indigo-white background. Both modes apply appropriate glow intensities. | Text | "Dark" |
LoadingStepsTable of {msg:Text} rows. One row per loading stage. The status label shows the msg at CurrentStep. The dot indicator count matches the row count. | Table | 4 steps |
CurrentStep1-based index of the active loading stage. Increment this from App.OnStart as each operation completes to advance the status label and active dot. | Number | 0 |
ErrorMessageWhen non-blank, hides the progress bar and dot indicators and shows this text in red below the divider. Set from App.OnStart if a ClearCollect or auth check fails. | Text | "" |
MinDisplayTimeMinimum milliseconds the screen stays visible regardless of how fast OnStart completes. When the timer elapses, OnReady fires. Prevents a flash on warm/cached loads. | Number | 1500 |
Output
| Property | Type | Description |
|---|---|---|
IsReadyTrue once MinDisplayTime has elapsed. Alternative to OnReady when you need a reactive formula rather than a callback, e.g. | Boolean | Driven by internal tmrMinDisplay. Same timer that fires OnReady. |
Events
| Event | Trigger | Typical handler |
|---|---|---|
OnReadyFires once when the internal | MinDisplayTime elapsed | Set(gAppReady, true) |
Implementation Details
Animated ring via Timer
A hidden Timer inside cntRing runs on a 1200ms repeat loop. The ring BorderColor opacity fades from 0.55 → 0 and BorderThicknessgrows from 1 → 5px as the timer progresses, creating a pulse-out effect without any animation APIs. The ring color is hardcoded to the default blue — Power Fx has no channel extraction functions to dynamically derive alpha from a Color value.
LoadingSteps drives dot count
galDots uses Sequence(CountRows(LoadingSteps)) as its Items. TemplateSize is fixed at 12px with TemplatePadding 0. Width is computed as CountRows * 12 - 7 to account for the 7px gap between dots. Add or remove a row and the dot count updates automatically.
CurrentStep indexing
The status label uses Index(LoadingSteps, Max(CurrentStep, 1)).msg so it always shows a valid message even when CurrentStep is 0 (not yet started). Dots use ThisItem.Value = CurrentStep for the active state and < CurrentStep for completed.
Error state
When ErrorMessage is non-blank, pbrLoading and galDots hide via their Visible property. lblStatus_2 switches its Text to show ErrorMessage and its Color to RGBA(220, 38, 38, 1). The component stays visible — your app is responsible for showing a Dismiss button or retry action at the screen level.
OnReady and MinDisplayTime
A hidden tmrMinDisplay timer auto-starts with Duration = MinDisplayTime and does not repeat. When it ends, it calls cmpLoadingScreen.OnReady() via its OnTimerEnd property. The IsReady output evaluates the same timer reactively — use whichever fits your pattern. With OnReady = Set(gAppReady, true) and Visible = !gAppReady, if OnStart finishes early the screen waits for the timer; if it takes longer, gAppReady stays false and the screen stays up.
Wordmark via HtmlViewer
The wordmark is a single HtmlViewer control with a conditional accent <span>. The accent color is embedded using Substitute(JSON(AccentColor), """, "") — JSON() serializes the Color value to a CSS rgba() string, and Substitute strips the surrounding quotes. Thanks to community member Rory Callaghan for the JSON() trick. Width is automatic and AppNameAccent being blank omits the span entirely.
Background glows
Three SVG radial gradient images (imgGlowTL, imgGlowBR, imgGlowCenter) use the same Substitute(JSON(AccentColor), """, "") trick to inject the accent color into the SVG string dynamically. Each image stays square so the radial gradient maintains its circular shape — consolidating into one image would stretch the gradient on non-square screens. Dark mode uses higher opacity stops; light mode uses softer values.
Examples
Custom brand — Inventory app
cmpLoadingScreen.AppName = "Contoso"
cmpLoadingScreen.AppNameAccent = "Inventory"
cmpLoadingScreen.AppSubtitle = "Stock Management"
cmpLoadingScreen.LogoLetter = "C"
cmpLoadingScreen.Theme = "Dark"
cmpLoadingScreen.CurrentStep = gLoadStep
cmpLoadingScreen.OnReady = Set(gAppReady, true)
cmpLoadingScreen.Visible = !gAppReadyLight theme
cmpLoadingScreen.Theme = "Light"
// All other properties remain the same —
// light mode uses softer glow intensities
// and inverts text/background colorsError state — access denied
// App.OnStart
Set(gCurrentUser,
LookUp('User Profiles', Email = User().Email));
If(
IsBlank(gCurrentUser),
Set(gLoadError,
"Access denied. Contact your administrator."),
// continue loading...
);
// Component
cmpLoadingScreen.ErrorMessage = gLoadError
cmpLoadingScreen.OnReady = Set(gAppReady, true)
cmpLoadingScreen.Visible = !gAppReadyArchitecture
15 controls — 1 background rectangle, 3 glow images, 1 logo container (+ letter label), 1 animated ring container (+ timer), 1 HtmlViewer wordmark, 1 subtitle label, 1 divider rectangle, 1 progress bar, 1 status label, 1 dot gallery (+ dot container), 1 version label.
13 properties — 11 input, 1 output (IsReady), 1 event (OnReady).
Sizing — Width and Height both bind to App.Width / App.Height. Position the component at X=0, Y=0 and it covers the full screen.
cmpLoadingScreen (Width = App.Width, Height = App.Height)
├── tmrMinDisplay — Timer, MinDisplayTime ms, no-repeat
│ OnTimerEnd → cmpLoadingScreen.OnReady()
│ IsReady output = tmrMinDisplay.Value >= Duration
├── rctBackground — full-screen fill, Dark or Light
├── imgGlowTL — SVG radial gradient, top-left, AccentColor via JSON()
├── imgGlowBR — SVG radial gradient, bottom-right, AccentColor via JSON()
├── imgGlowCenter — SVG radial gradient, center ambient, AccentColor via JSON()
├── cntLoadingCenter — AutoLayout vertical, centered stack
│ ├── cntLogoWrap — 116×116 ManualLayout, gives ring breathing room
│ │ ├── imgLogoMark — 88×88 GroupContainer, AccentColor fill, X/Y 14
│ │ │ └── lblLogoLetter — LogoLetter, centered, white
│ │ └── cntRing — border pulses via tmrRing, hardcoded blue, X/Y 8
│ │ └── tmrRing — Timer, 1200ms repeat, Visible: false
│ ├── htxWordmark — HtmlViewer, AccentColor injected via Substitute(JSON())
│ ├── lblSubtitle — Upper(AppSubtitle), letter-spaced
│ ├── rctDivider — 52×2 AccentColor line
│ ├── pbrLoading — Progress control, Indeterminate, hidden on error
│ ├── lblStatus — shows ErrorMessage in red when set, else step msg
│ └── galDots — Horizontal gallery, hidden on error
│ └── cntDot — 5×5 dot, AccentColor fill based on step state
└── lblVersion — CompanyName · AppVersion, AccentColor, bottom of screenCommunity
Use the toolbar to format · or type markdown directly