npx skills add ...
npx skills add forcedotcom/sf-skills --skill implementing-ui-bundle-file-upload
MUST activate when the project contains a uiBundles/*/src/ directory and the task involves uploading, attaching, or dropping files. Use this skill when adding file upload functionality to a UI bundle app. Provides progress tracking and Salesforce ContentVersion integration. This feature provides programmatic APIs ONLY — build custom UI using the upload() API. ALWAYS use this instead of building file upload from scratch with FormData or XHR.
npx skills add forcedotcom/sf-skills --skill implementing-ui-bundle-file-upload
When the user wants file upload functionality in a React UI bundle, follow this workflow. This feature provides APIs only — you must build the UI components yourself using the provided APIs.
The package exports programmatic APIs, not React components or hooks. You will:
upload() function to handle file uploads with progress trackingonProgress callbackDo NOT:
<FileUpload /> — they are not exporteduseFileUpload — they are not exportedThe source code contains reference components for demonstration, but they are not available as imports. Use them as examples to build your own UI.
Dependencies are automatically installed:
@salesforce/ui-bundle (API client)@salesforce/sdk-data (data SDK)Upload files to Salesforce and get back contentBodyId for each file. No ContentVersion record is created.
When to use:
Upload files and immediately link them to an existing Salesforce record by creating ContentVersion records.
When to use:
Upload files without a record, then link them after the record is created.
When to use:
The package provides the backend — you build the frontend. Here's a minimal example:
The onProgress callback fires multiple times for each file as it moves through stages:
| Status | When | Progress Value |
|---|---|---|
"pending" | File queued for upload | 0 |
"uploading" | Upload in progress (XHR) | 0-100 (percentage) |
"processing" | Creating ContentVersion (if recordId provided) | 0 |
"success" | Upload complete | 100 |
"error" | Upload failed | 0 |
Always provide visual feedback:
Use an AbortController to allow users to cancel uploads:
If the user wants to upload files to their own profile or personal library:
Main upload API that handles complete flow with progress tracking.
Returns: Promise<FileUploadResult[]>
Manually create a ContentVersion record from a previously uploaded file.
Parameters:
file — File object (used for metadata like name)contentBodyId — ContentBody ID from previous uploadrecordId — Record ID for FirstPublishLocationIdReturns: ContentVersion ID if successful
Get the current user's Salesforce ID.
Returns: Current user ID
Build your own dropzone using native events:
User asks for file upload functionality:
Ask about record context:
Based on response:
recordIdgetCurrentUserId()Build the UI:
Test the implementation:
contentBodyId is returnedrecordId was provided, verify contentVersionId is returnedThe package includes a reference implementation in src/features/fileupload/ with:
FileUpload.tsx — Complete component with dropzone and dialogFileUploadDialog.tsx — Progress tracking dialogFileUploadDropZone.tsx — Drag-and-drop zoneuseFileUpload.ts — React hook for state managementThese are NOT exported but can be viewed as examples. Read the source files to understand patterns for building your own UI.
Upload fails with CORS error:
localhostNo progress updates:
onProgress callback is providedContentVersion not created:
recordId is provided to upload() functionFiles upload but don't appear in record:
recordId is correctcontentVersionId in results)upload() API<FileUpload /> component — it's not exporteduseFileUpload hook — it's not exported