3rd-Party Declarations · Part 1 of 3

Foundations: the list, the app, and the multi-row form

This part takes you from an empty canvas to a working multi-row declaration form: the 3rd party inventory list verified, a tablet app connected to it, and a gallery where users add, fill and delete system records — with every keystroke safely stored. Every step is self-contained, and every name, number and formula has a copy button.

10 steps 1 list verified 14 fields wired smoke test 🧪
0 of 10 steps done

What you're building

The series in one lineA Power Apps declaration form where business users record one or more third-party applications (14 required fields each), review them, and submit them all at once into the existing 3rd party inventory SharePoint list — with an automatic email to the IAM team. Part 1 builds the form itself; Part 2 adds validation and guidance; Part 3 wires up submission, notification and publishing.
The architecture, in one paragraphEvery row of the form lives in a local collection called colSystems — not in the on-screen controls. Each input immediately writes its value back into the collection the moment it changes. That one habit makes the whole app safe: rows can scroll out of sight, rows can be deleted from the middle, and nothing is ever lost or shuffled, because the collection — not the controls — is the single source of truth. Step A10 will make you prove this to yourself.
Two placeholders to substituteWherever you see <YOUR-SITE-URL> (your SharePoint site) or <IAM-DL-EMAIL> (the IAM distribution list address), substitute your own values. Everything else is paste-as-is.
How to read this guide — click vs enterEvery step uses the same three markers, so you always know where to look. A navy button like + Insert is something you click in Power Apps or SharePoint — a menu, a button, or a property name. An amber chip like galSystems is a value you enter — tap the chip to copy it (the ⧉ mark is the reminder), then paste it where the step says. A key cap like Ctrl+A is pressed on the keyboard. Dark boxes are complete formulas with their own Copy button. Paste, never retype.
How every insert worksClick + Insert on the left rail → type the control name into the search box → click it. The only search terms this guide uses: Text label · Text input · Drop down · Button · Rectangle · Blank vertical gallery. After inserting, rename the control: double-click its name in the Tree view → paste the new name → Enter.

First, the list

A1Check the 3rd party inventory list

The list already exists — this step makes sure it looks exactly the way the formulas in Part 3 expect. Open <YOUR-SITE-URL> in the browser → gear icon (top right)Site contents → click 3rd party inventorygear icon again → List settings. The Columns section lists every column with its Type right beside the name — that's where you confirm everything below. Compare it against this table:

#Display nameExpected typeForm fills it?
1Application NameText (likely the renamed Title)Yes
2Vendor/ Provider Name — space after the /TextYes
3Business owner — lowercase oTextYes
4Application PurposeMultiline textYes
5IT CustodianTextYes
6Admin Accounts UsedTextYes
7Permissions / Access levels — lowercase lMultiline textYes
8Support / Vendor Contact InformationTextYes
9IAM RoleText — assumedYes
10Access LinkTextYes
11Division␠trailing space in the nameText — assumedYes
12StatusText — assumedYes
13Submission DateDate and Time — assumedYes (auto)
14IAM NotesTextNo
15Submission CycleTextNo
16Handover StatusText — assumedYes
17Number of AccountsText — assumedYes
18Report ExportYes/NoNo
19Onboarded to IAM PlatformYes/NoNo
20Access Review StatusTextNo
21Review FrequencyTextNo

Six assumed types — glance and confirm

Six columns marked "assumed" above had ambiguous types; this guide commits to the common-sense ones below (the live list data backs them). While you're in List settings, glance at each — and if one differs, nothing breaks: step C5 (Part 3) has a one-line fix per column, clearly marked.

  1. IAM Role — Single line of text
  2. Division␠ (the one with the trailing space) — Single line of text
  3. Status — Single line of text
  4. Handover Status — Single line of text
  5. Number of Accounts — Single line of text
  6. Submission Date — Date and Time

Only note a column down if its type is different from the list above — that note is all C5 needs.

Two checks and one addition while you're here:

  1. Title check. If Application Name is the renamed built-in Title column (it usually is), that's fine. What matters: there must be no separate Title column still marked "Require that this column contains information" — that would make every submission fail in Part 3. To check: List settings → Columns → click Title → "Require that this column contains information" must be No.
  2. Add the audit columns (skip if they already exist). List settings → Create column → name Responder Name → type Single line of textOK (or, from the list view itself: + Add columnSingle line of text). Repeat for Responder Email.
The quirky names are load-bearingFour column names contain deliberate-looking accidents — Vendor/ Provider Name (space after the slash), Business owner (lowercase o), Permissions / Access levels (lowercase l), and Division (trailing space). Do not rename them — live data and the formulas in this guide both use them as-is. In Power Apps you'll always accept IntelliSense autocomplete rather than hand-typing these. And when this guide writes Division␠, the ␠ just marks the invisible trailing space — on screen the column looks like plain "Division".
Check before moving onAll 21 columns present with matching names · the six assumed types glanced at (noted any that differ) · no separate required Title column · Responder Name and Responder Email exist as Single line of text columns.

The app shell

A2Create the app and set three settings
  1. Go to make.powerapps.com (check the correct environment, top right) → CreateStart with a blank canvasTablet size. If a dialog asks for the app's name right away, paste Third-Party Application Declaration there. Studio opens with an empty Screen1.
  2. Settings (gear icon, or FileSettings) → Display: confirm size is 1366 × 768.
  3. Settings has a search box — type modern to find Modern controls and themes → turn it OFF. This guide names classic properties (HintText, Default, BorderColor) — modern controls would rename half of them.
  4. Same search box → type error to find Formula-level error management → turn it ON. Part 3's submit formula uses IfError, which needs this switch.
  5. Tree view → double-click Screen1 → rename to scrMain.
Save earlyIf you weren't asked for a name at creation: FileSave → paste Third-Party Application Declaration. Autosave takes over from here.
Check before moving onAn empty tablet app named and saved · Tree view shows a single screen called scrMain · modern controls off · formula-level error management on.
A3Connect the SharePoint list
  1. Left rail → Data (cylinder icon) → Add data → search SharePoint → pick the SharePoint connector (sign in if asked).
  2. In the site picker, paste <YOUR-SITE-URL> (or pick the site from Recent) → Connect.
  3. Tick 3rd party inventory in the list of lists → Connect.
Nothing to configureThe connection brings the columns along, quirky names and all. You won't touch the data source again until Part 3 — but connecting now means IntelliSense already knows every column name when you get there.
Check before moving onThe Data pane lists 3rd party inventory as a connected data source.
A4App.OnStart — collections, flags, and the first blank row

Tree view → click App → property dropdown (top-left, next to the fx bar) → OnStartCtrl+A → paste:

App · OnStart

Set(gblColorBrand, ColorValue("#C8102E")); Set(gblColorInk, ColorValue("#1B2436")); Set(gblColorPaper, ColorValue("#F4F5F8")); ClearCollect(colIAMRoles, ["Manage", "Govern", "Not Involved"]); ClearCollect(colStatusValues, ["Active", "Decommissioned"]); ClearCollect(colHandoverValues, ["Handover Not Required", "Handed Over", "Pending Handover"]); ClearCollect(colDivisions, ["Operations & Administration", "Information Technology", "Financial Planning & Control", "Human Resources", "Strategy & Transformation", "Marketing & Communications", "Corporate & Business Development", "Remedial", "In - Business Risk", "Treasury & Investment", "Private Banking & Wealth Management", "International Banking", "Wholesale Banking", "Retail Banking", "Corporate Secretariat", "Information Security", "Risk Management", "Credit & Overseas Risk", "Compliance & AML", "Internal Audit", "Legal"]); Set(gblShowErrors, false); Set(gblShowConfirm, false); Set(gblShowSuccess, false); Set(gblSubmitting, false); Set(gblNextSeq, 2); ClearCollect(colSystems, {RowID: GUID(), SeqNo: 1, AppName: "", Vendor: "", BizOwner: "", Purpose: "", Custodian: "", AdminAccts: "", Permissions: "", SupportContact: "", IAMRole: "", AccessLink: "", Division: "", Status: "", Handover: "", NumAccts: ""})

Then run it once: Tree view → hover AppRun OnStart.

What just happenedThree theme colors · four dropdown source collections (three roles, two statuses, three handover states, 21 divisions) · four false flags for later parts · a sequence counter starting at 2 · and colSystems — the form's single source of truth — seeded with one blank row (SeqNo 1, every field empty).
Run OnStart resets the formRe-running OnStart wipes any in-progress rows back to one blank row. While building, that's expected — you'll do it on purpose. Just don't be surprised.
Check before moving onLeft rail → Variables (x icon) → Collections: five collections exist. colSystems holds exactly 1 row; colDivisions holds 21 rows.
A5The header band

Four controls on scrMain. For each: + Insert → search box → the control's search term → click it → rename in the Tree view (double-click the name → paste → Enter) → set X/Y/Width/Height in the Properties pane on the right. Two standing motions, used here and in every later step: every quoted Text value goes in via property dropdown (top-left, next to the fx bar) → TextCtrl+A → paste (quotes included); every colour goes in via property dropdown → Color (or Fill) → Ctrl+A → paste.

  1. + Insert → search Rectangle → rename recHeader → X 0 · Y 0 · Width 1366 · Height 80. Property dropdown → FillCtrl+A → paste: gblColorBrand
  2. + Insert → search Text label → rename lblAppTitle → X 24 · Y 10 · Width 800 · Height 36 → Text: "Third-Party Application Declaration" → right pane: Font size 22, Bold → Color: Color.White.
  3. + Insert → search Text label → rename lblAppSubtitle → X 24 · Y 46 · Width 800 · Height 26 → Text: "Declare the third-party systems your division uses — all fields are required" → right pane: Font size 14 → Color: Color.White.
  4. + Insert → search Text label → rename lblUserBadge → X 1020 · Y 24 · Width 322 · Height 32 → right pane: Font size 14, text alignment Right → Color: Color.White. Then property dropdown → TextCtrl+A → paste:

lblUserBadge · Text

User().FullName
Brand colour, one variablegblColorBrand is the brand red set in OnStart. If branding ever changes, one line in OnStart re-skins the app.
Check before moving onA red band across the top: bold title, smaller subtitle, and your own name sitting right-aligned in the band.

The multi-row form

A6The gallery — one card per system
  1. + Insert → search Blank vertical gallery → click it. Rename it galSystems.
  2. The Items panel may pop up asking for a data source — choose colSystems (or set the property dropdown → ItemsCtrl+A → paste colSystems).
  3. Properties pane: X 0 · Y 96 · Width 1366 · Height 580.
  4. Property dropdown → TemplateSizeCtrl+A → type: 600
  5. Now click the pencil icon in the gallery's top-left corner — this puts you inside the template, so everything you insert next lands in the row, not on the screen. + Insert → search Rectangle → rename recRowCard → X 8 · Y 8 · Width 1318 · Height 584. Then three property pastes: FillCtrl+ARGBA(255, 255, 255, 1) · BorderColorCtrl+ARGBA(201, 204, 213, 1) · BorderThicknessCtrl+A1.
  6. Still inside the template: + Insert → search Text label → rename lblRowNum → X 16 · Y 14 · Width 200 · Height 28Bold. Property dropdown → TextCtrl+A → paste:

lblRowNum · Text

"System " & ThisItem.SeqNo
  1. Still inside the template: + Insert → search Button → rename btnDeleteRow → X 1180 · Y 14 · Width 130 · Height 32 → Text: "Delete Row" (property dropdown → TextCtrl+A → paste). Property dropdown → OnSelectCtrl+A → paste:

btnDeleteRow · OnSelect

Remove(colSystems, ThisItem)
Fixed height, on purposeTemplateSize stays a fixed 600. Do not switch to a flexible-height gallery — inputs inside flexible-height galleries misbehave, and this guide's geometry assumes fixed rows.
Check before moving onOne white card in the gallery reading System 1 with a Delete Row button top-right. (Clicking Delete now removes the only row — Tree view → AppRun OnStart brings it back.)
A7Left column — seven fields

Seven label + input pairs, all inside the gallery template (pencil icon first — check the breadcrumb above the canvas says you're in galSystems). The drill for every field: + Insert → search Text label, rename, position, set Text (property dropdown → TextCtrl+A → paste, quotes included) · + Insert → search Text input, rename, position · property dropdown → DefaultCtrl+A → paste · property dropdown → OnChangeCtrl+A → paste. All labels and inputs: X 16 · Width 630. Labels Height 20, inputs Height 40.

1 · Application Name. Label lblAppName at Y 48, Text "Application Name". Input txtAppName at Y 72:

txtAppName · Default

ThisItem.AppName

txtAppName · OnChange

Patch(colSystems, ThisItem, {AppName: Self.Text})

2 · Vendor/Provider Name. Label lblVendor at Y 120, Text "Vendor/Provider Name". Input txtVendor at Y 144:

txtVendor · Default

ThisItem.Vendor

txtVendor · OnChange

Patch(colSystems, ThisItem, {Vendor: Self.Text})

3 · Business Owner. Label lblOwner at Y 192, Text "Business Owner". Input txtOwner at Y 216:

txtOwner · Default

ThisItem.BizOwner

txtOwner · OnChange

Patch(colSystems, ThisItem, {BizOwner: Self.Text})

4 · Application Purpose — this one is multiline. Label lblPurpose at Y 264, Text "Application Purpose". Input txtPurpose at Y 288, and additionally property dropdown → ModeCtrl+A → paste TextMode.MultiLine:

txtPurpose · Default

ThisItem.Purpose

txtPurpose · OnChange

Patch(colSystems, ThisItem, {Purpose: Self.Text})

5 · IT Custodian. Label lblCustodian at Y 336, Text "IT Custodian". Input txtCustodian at Y 360:

txtCustodian · Default

ThisItem.Custodian

txtCustodian · OnChange

Patch(colSystems, ThisItem, {Custodian: Self.Text})

6 · Admin Accounts Used. Label lblAdminAccts at Y 408, Text "Admin Accounts Used". Input txtAdminAccts at Y 432:

txtAdminAccts · Default

ThisItem.AdminAccts

txtAdminAccts · OnChange

Patch(colSystems, ThisItem, {AdminAccts: Self.Text})

7 · Permissions / Access Levels — multiline again. Label lblPermissions at Y 480, Text "Permissions / Access Levels". Input txtPermissions at Y 504, Mode → Ctrl+A → paste TextMode.MultiLine:

txtPermissions · Default

ThisItem.Permissions

txtPermissions · OnChange

Patch(colSystems, ThisItem, {Permissions: Self.Text})
Why every input patches itselfDefault reads the row's stored value; OnChange writes edits straight back into colSystems. Because both use ThisItem/Self, the formulas are identical in every row and every field except the field name — and the collection is always up to date, no matter what the gallery does with its on-screen controls.
Check before moving onSeven stacked fields down the left half of the card. Type into any of them, then click somewhere else — OnChange fires when you leave the field — and open Variables → colSystems: the value is in the collection.
A8Right column — three inputs and four dropdowns

Same drill, right half of the card: everything at X 676 · Width 630, labels Height 20, inputs Height 40. Text values go in the same way as A7 (property dropdown → TextCtrl+A → paste, quotes included). Four of these are Drop down controls (+ Insert → search Drop down) — set each one's properties in this order: ItemsAllowEmptySelectionDefaultOnChange.

1 · Support / Vendor Contact. Label lblSupport at Y 48, Text "Support / Vendor Contact". Text input txtSupport at Y 72:

txtSupport · Default

ThisItem.SupportContact

txtSupport · OnChange

Patch(colSystems, ThisItem, {SupportContact: Self.Text})

2 · IAM Role — first dropdown. Label lblIAMRole at Y 120, Text "IAM Role". Drop down drpIAMRole at Y 144. Set Items first (box below), then property dropdown → AllowEmptySelectionCtrl+A → type true, then Default and OnChange:

drpIAMRole · Items

colIAMRoles

drpIAMRole · Default

ThisItem.IAMRole

drpIAMRole · OnChange

Patch(colSystems, ThisItem, {IAMRole: Self.Selected.Value})

3 · Access Link. Label lblAccessLink at Y 192, Text "Access Link". Text input txtAccessLink at Y 216:

txtAccessLink · Default

ThisItem.AccessLink

txtAccessLink · OnChange

Patch(colSystems, ThisItem, {AccessLink: Self.Text})

4 · Division. Label lblDivision at Y 264, Text "Division". Drop down drpDivision at Y 288, AllowEmptySelection true:

drpDivision · Items

colDivisions

drpDivision · Default

ThisItem.Division

drpDivision · OnChange

Patch(colSystems, ThisItem, {Division: Self.Selected.Value})

5 · Status. Label lblStatus at Y 336, Text "Status". Drop down drpStatus at Y 360, AllowEmptySelection true:

drpStatus · Items

colStatusValues

drpStatus · Default

ThisItem.Status

drpStatus · OnChange

Patch(colSystems, ThisItem, {Status: Self.Selected.Value})

6 · Handover Status. Label lblHandover at Y 408, Text "Handover Status". Drop down drpHandover at Y 432, AllowEmptySelection true:

drpHandover · Items

colHandoverValues

drpHandover · Default

ThisItem.Handover

drpHandover · OnChange

Patch(colSystems, ThisItem, {Handover: Self.Selected.Value})

7 · Number of Accounts. Label lblNumAccts at Y 480, Text "Number of Accounts". Text input txtNumAccts at Y 504, and additionally property dropdown → FormatCtrl+A → paste TextFormat.Number:

txtNumAccts · Default

ThisItem.NumAccts

txtNumAccts · OnChange

Patch(colSystems, ThisItem, {NumAccts: Self.Text})
AllowEmptySelection is not optionalA classic dropdown silently auto-selects its first item unless AllowEmptySelection is true with a blank Default. Skip it and every new row is born with "Manage" / "Operations & Administration" pre-picked — which quietly defeats the mandatory-field validation coming in Part 2.
Check before moving onFourteen fields fill the card in two columns. All four dropdowns start empty, and each offers the right values (3 roles · 21 divisions · 2 statuses · 3 handover states).
A9Footer bar — Add System and the row count

Back out of the gallery template first — click empty canvas or press Esc, and check the breadcrumb: the next three controls belong to scrMain, not the template.

  1. + Insert → search Rectangle → rename recFooter → X 0 · Y 692 · Width 1366 · Height 76 → Fill: gblColorInk (property dropdown → FillCtrl+A → paste).
  2. + Insert → search Button → rename btnAddSystem → X 24 · Y 710 · Width 200 · Height 40 → Text: "+ Add System" (property dropdown → TextCtrl+A → paste). Property dropdown → OnSelectCtrl+A → paste:

btnAddSystem · OnSelect

Collect(colSystems, {RowID: GUID(), SeqNo: gblNextSeq, AppName: "", Vendor: "", BizOwner: "", Purpose: "", Custodian: "", AdminAccts: "", Permissions: "", SupportContact: "", IAMRole: "", AccessLink: "", Division: "", Status: "", Handover: "", NumAccts: ""}); Set(gblNextSeq, gblNextSeq + 1)
  1. + Insert → search Text label → rename lblSystemCount → X 240 · Y 716 · Width 420 · Height 28 → Color: Color.White (property dropdown → ColorCtrl+A → paste). Then property dropdown → TextCtrl+A → paste:

lblSystemCount · Text

CountRows(colSystems) & " system(s) in this declaration"
The footer isn't finishedThe Submit button and the form-level error message join this bar in Part 2 — the space to the right is reserved for them.
Check before moving onDark footer bar with + Add System and a live count. Click the button: a fresh System 2 card appears in the gallery and the count says 2. Delete it: the count says 1.
A10The smoke test — prove the architecture

Five minutes that buy total confidence in everything Parts 2 and 3 build on. Press F5 (Preview):

  1. Click + Add System twice — three cards: System 1, 2, 3.
  2. Give each row a distinct Application Name — Alpha, Bravo, Charlie — and fill a couple more fields in each, including a dropdown pick.
  3. Scroll test: scroll the gallery so System 1 leaves the screen, then scroll back. Every value is still there.
  4. Delete-the-middle test: click Delete Row on System 2 (Bravo). Two cards remain — System 1 still says Alpha, System 3 still says Charlie. Nothing shifted, nothing bled between rows.
  5. Leave Preview (Esc). Left rail → Variables → Collections → colSystems: the surviving two rows, exactly as typed. Type one more character in any field and watch the collection update on the next refresh — every keystroke lands in the collection, not just on screen.
Why we never read the controlsGalleries recycle their on-screen controls: scroll far enough and the same physical input is redrawn for a different row; delete a row and control state can shift into its neighbour. Apps that read control values at submit time lose data to exactly these two behaviours. This app never will — Parts 2 and 3 validate and submit from colSystems only, which you have just watched stay correct through both.
Check before moving onBoth tests pass: scrolled-away values persist, and deleting the middle row leaves the other rows' values untouched and correctly paired. The foundation is solid — on to Part 2. 🏗️