PPowerApps UI
ComponentsLayoutsTemplatesAbout
P
PowerApps UI
Open Source

Production-ready UI components and patterns for Power Apps developers.

MIT License

Product

  • Components
  • Layouts
  • Templates
  • Starter Kits
  • About
  • Cheat Sheet
  • Documentation

Developers

  • Getting Started
  • Suggest Idea
  • Submit Component
  • Report Issues

Resources

  • Changelog
  • Newsletter
  • Best Practices
  • Design System
© 2026 PowerApps UI. Open source under MIT License.
Built byRodas Yonass
Privacy Policy•Terms of Service•MIT License
ComponentsFile Upload

File Upload

Upload files to SharePoint document libraries with validation, preview, and metadata display. Supports multiple file types and size restrictions.

cmpFileUpload.yaml
  1. 1. Go to the Components tab (right side panel, next to Screens)
  2. 2. Click New component — this creates a blank component
  3. 3. Click outside the new component to deselect it
  4. 4. Paste the YAML with Ctrl+V / ⌘V

This component requires Modern controls to be enabled. Settings → Updates → Preview → Modern controls and themes

Preview

Theme:

Upload Documents

Click to select files

or drag and drop

Accepted: All file types

Max size: 10 MB • Max files: 3

Budget_Report_2024.xlsx

2.4 MB

Ready

Team_Photo.jpg

3.8 MB

Ready

Large_Video_File.mp4

15.2 MB

Failed

File exceeds 10 MB limit

Upload Settings

Allowed File Types

Max File Size

Max Files

Show Validation

Component Features

  • File size validation
  • File type filtering
  • Multiple file support
  • SharePoint integration

A documents panel for Canvas apps: a drag-and-drop staging area, a list of the files that already exist, and per-row preview, download and delete actions.

No connectors required. The component queries nothing and writes nothing. It stages files and raises events, and your app decides what a save or a delete means. That is what lets it drop into any app and work immediately against the sample rows.


What it does not do

Worth reading before the property list, because it is the shortest route to knowing whether this is the component you want.

  • It does not upload. OnSave hands you the staged files. Writing them to SharePoint, Dataverse or anywhere else is yours, normally through a Flow. The recipe below is a complete working one.
  • It does not delete. OnDelete tells you which row was tapped. A document already in a library is not the component's to remove.
  • It does not query. Items is an input. The component never sees your data source, which is why it has no connector dependency and no delegation limits of its own.
  • It does not filter by file type. AcceptedText prints a hint. The underlying Attachments control enforces nothing about type, so a real restriction belongs in your Flow.

Install

  1. Components → New component → Import from code
  2. Paste cmpFileUpload.yaml
  3. Add the component to a screen

Then three things that a paste does not carry, all of which are Power Apps behaviour rather than anything about this component:

  • Set the instance Width by hand. A pasted instance arrives at 600 regardless of what the property says. Height survives; Width does not. Reproduced Studio to Studio by duplicating a screen.
  • Bind Height to DesiredHeight, or drop the instance in an AutoLayout container and let it stretch.
  • Pass Style, Colors and TypeColors explicitly if you are customising them. A Record or Table input's default does not reach a pasted instance. The component Coalesces every read against its documented defaults, so omitting them is safe, but a half-filled record is not.

Quick start

Everything below is optional. This renders a working panel against sample data:

Height: =cmpFileUpload_1.DesiredHeight
Items:  =colMyDocs

colMyDocs needs the columns Id, Name, SizeBytes, UploadedOn, UploadedBy, Ext. SizeBytes is a number of bytes rather than a formatted string, because the footer totals it.


Properties

Inputs

PropertyTypeDefaultDescription
AcceptedTextText"PDF, DOC, XLSX, PNG"File types named in the hint line under the dropzone. The size limit is appended from MaxFileSize, so do not type it here.
AllowDeleteBooleantruePERMISSION. The bin on each existing document row.
AllowUploadBooleantruePERMISSION AND LAYOUT AT ONCE. The dropzone and the Upload and Cancel buttons.
ColorsRecordsee belowAll ten keys are required. A missing key resolves blank and paints nothing with no error.
HeaderTextText"Documents"Heading above the dropzone. ShowHeader false hides it.
ItemsTablesee belowDocuments that ALREADY EXIST. The component does not query anything, so it carries no connector dependency.
MaxFileSizeNumber25Megabytes. Shown in the hint line AND passed to the Attachments control's MaxAttachmentSize, so it is genuinely enforced at the point of staging.
MaxFilesNumber5Cap on STAGED files, enforced in OnAddFile and passed to the Attachments control. Existing documents in Items are not counted against it.
ShowFooterBooleantrueThe count and total size line, and the Download All link.
ShowHeaderBooleanfalseThe HeaderText line.
ShowRowActionsBooleantrueThe view, download and bin icons on each existing document row.
StyleRecordsee belowAll eleven keys are required. DropHeight is the dashed zone.
TypeColorsTablesee belowMaps a file extension to the colour of its tile. Ext is matched against Items.Ext case insensitively.

Outputs

OutputTypeDescription
DesiredHeightNumberHeader plus dropzone plus both lists plus footer for the current flags and row counts. Bind the instance Height to this, or let a parent AutoLayout stretch the instance instead.
DocCountNumberRow count of Items, the documents that already exist. Does not include staged files.
StagedCountNumberNumber of files staged but not yet saved.
StagedFilesTableThe staged attachments, in whatever shape the Attachments control produced. Read this inside OnSave and hand it to a Flow. It is NOT cleared on save, see OnSave.
StagedFilesDataTableA TABLE of { Name, ContentBytes } with clean base64. POPULATED WHEN UPLOAD IS PRESSED and only meaningful inside the OnSave handler. Use this when your Flow takes a TEXT parameter.
TappedIdTextId of the document whose row action was last tapped. Only meaningful inside OnView, OnDownload or OnDelete.
TappedNameTextName of the document whose row action was last tapped.
TotalBytesNumberSum of SizeBytes across Items. Staged files are excluded, because the Attachments control does not expose a reliable size.
TotalTextTextTotalBytes formatted the same way a row is, KB under a megabyte and MB above.

Events

EventFires whenRead in handler
OnCancelCancel is tapped, after the staged list is cleared—
OnDeleteThe bin icon on an existing document is tappedTappedId, TappedName
OnDownloadThe download icon is tappedTappedId, TappedName
OnDownloadAllThe footer Download All link is tappedDocCount
OnSaveUpload is tappedStagedFiles, StagedFilesData, StagedCount
OnViewThe eye icon is tappedTappedId, TappedName

Recipe: SharePoint document library via Power Automate

The complete working path, including the part that silently fails if you skip it.

The trap

The Attachments control does not give you file bytes. Its Value is an appres://blobmanager/... link, an internal temporary Power Apps identifier. Power Automate cannot resolve it, so passing it to a Flow writes a zero byte file with no error anywhere.

Which output you send depends on your Flow's trigger:

Your Flow trigger takesSend thisWhy
A File input on the Power Apps (V2) triggerStagedFilesPower Apps resolves the blob natively. No base64 needed.
A Text inputStagedFilesDataA table of { Name, ContentBytes }. Loop it with ForAll, or wrap it in JSON() for a whole-batch Flow.

The File input is the easiest and is what the recipe below uses.

All three are only meaningful inside OnSave. StagedFilesData in particular is assembled at the moment Upload is pressed, so reading it anywhere else returns the previous batch or nothing. Power Fx will not let a component build binary data outside a behaviour formula, so it cannot be assembled continuously the way the other outputs are. In practice this is invisible: OnSave is the only place you would ever read it.

The Flow

Trigger: Power Apps (V2) with a File input. Note that File inputs are optional by default while every other type is required, which is what makes the folder-creation call below work.

Then Create file:

FieldValue
Site Addressyour site
Folder Pathyour library
File NametriggerBody()['file']['name']
File ContenttriggerBody()['file']['contentBytes']

Finish with Respond to a PowerApp or flow returning one Text output. This is not decoration: without a Respond action Power Apps does not wait for the Flow, so your refresh runs before the file exists and IfError cannot catch anything.

OnSave

=Set(gblBusy, true);
Clear(colFailed);
ForAll(
    cmpFileUpload_1.StagedFiles As f,
    If(
        IsError(
            UploadDocument.Run({ file: { name: f.Name, contentBytes: f.Value } })
        ),
        Collect(colFailed, { Name: f.Name })
    )
);
Set(gblBusy, false);
If(
    IsEmpty(colFailed),
    Refresh(MyLibrary);
    ClearCollect(colMyDocs, <your projection>);
    Reset(cmpFileUpload_1);
    Notify("Uploaded.", NotificationType.Success),
    Notify(
        CountRows(colFailed) & " failed: " & Concat(colFailed, Name, ", "),
        NotificationType.Error
    )
)

Three things about the order.

Reset() is last and only on success. The component deliberately keeps the staged files after OnSave so it still holds the only copy until the write is confirmed. Reset() clears both the collection and the Attachments control.

Refresh() before the re-read is not optional. Power Apps caches the source, so without it the files you just uploaded are not in the collection and it looks like nothing happened.

IsError() rather than IfError() returns a Boolean whatever the Flow returns, so the formula survives adding or removing the Respond action.

Reading the library back

A document library returns folders and files in one table, so filter the folders out or every folder renders as a document row:

=ClearCollect(
    colMyDocs,
    ForAll(
        Filter(MyLibrary, '{IsFolder}' = false) As d,
        {
            Id:         Text(d.ID),
            Name:       d.'{FilenameWithExtension}',
            SizeBytes:  0,
            UploadedOn: d.Modified,
            UploadedBy: d.'Created By'.DisplayName,
            Ext:        Lower(Last(Split(d.'{FilenameWithExtension}', ".")).Value)
        }
    )
)

There is no file size column. The SharePoint connector does not expose one to Power Apps, so SizeBytes is 0 and the footer total reads 0 KB. If size matters, add a Number column to the library and write it from the Flow; length(triggerBody()['file']['contentBytes']) is about 4/3 of the true size and close enough for a display string.

Projected with ForAll building a record rather than ShowColumns and RenameColumns, because those take a column name and whether it is written bare or quoted depends on an app level setting.

Preview and download

{Link} is on the record, so neither needs a Flow:

OnView:     =Launch(LookUp(MyLibrary, ID = Value(cmpFileUpload_1.TappedId)).'{Link}')
OnDownload: =Download(LookUp(MyLibrary, ID = Value(cmpFileUpload_1.TappedId)).'{Link}')

Recipe: permissions

AllowUpload: =true
AllowDelete: =gblIsAdmin

Two independent switches, and all four combinations are useful:

AllowUploadAllowDeleteWhat the user gets
truetrueEverything
truefalseUpload, view, download. Cannot remove anything.
falsetrueNo dropzone, but can still delete
falsefalseRead, preview and download only

The second row is the common one: everyone contributes, only an owner removes. The third is usually layout rather than permission, for when there is no room for a dropzone or uploading lives behind a button elsewhere on the screen.

ShowRowActions is separate again. It is the layout switch for the whole icon cluster, where AllowDelete is the permission for the bin inside it. Hiding the icons to save space and forbidding deletion are different decisions.


Limits

Enforced file sizeMaxFileSize, passed to the control. Decimal MB, so 1,000,000 bytes.
Platform ceilingAround 50MB per file regardless of MaxFileSize, with failures earlier on slow connections.
Staged file countMaxFiles. Existing documents do not count against it.
File typeNot enforced. AcceptedText is a hint only.
Instances per screenOne. The staged list lives in a component-scoped global, so two instances on a screen share it.

The row and footer size labels divide by 1,048,576 (binary MiB) while the upload limit counts decimal MB. They disagree by about 5%, so a file displaying as "23.9 MB" can still be rejected at a limit of 25. This is deliberate: file managers report binary and upload limits are quoted decimal, and matching them would make one of the two wrong.


Accessibility

  • Every interactive control is named, by AccessibleLabel on modern controls and by Tooltip on classic ones, which have no AccessibleLabel property.
  • Row action tooltips name the file, so "Delete Budget.xlsx" rather than "Delete".
  • Decorative icons are TabIndex: -1 and out of the tab order. Only the buttons underneath them take focus.
  • Upload and Cancel are both disabled with nothing staged, so neither fires an event on an empty list.

Get new components and templates when they drop

One email when something new ships. Unsubscribe anytime.

Community

Use the toolbar to format · or type markdown directly