/experience-ui-bundle-file-upload-generate
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
$ npx -y skills add forcedotcom/sf-skills --skill experience-ui-bundle-file-upload-generate --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/experience-ui-bundle-file-upload-generate
Context preview
The summary Claude sees to decide when to auto-load this skill.
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
SKILL.md
experience-ui-bundle-file-upload-generate.SKILL.mdname: experience-ui-bundle-file-upload-generate
description: "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."
metadata:
version: "1.0"
relatedSkills:
- "experience-ui-bundle-salesforce-data-access"
cliTools:
- tool: ["npm"]
semver: ">=7.0.0"File Upload API (workflow)
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.
CRITICAL: This is an API-only package
The package exports **programmatic APIs**, not React components or hooks. You will:
- Use the `upload()` function to handle file uploads with progress tracking
- Build your own custom UI (file input, dropzone, progress bars, etc.)
- Track upload progress through the `onProgress` callback
**Do NOT:**
- Expect pre-built components like `<FileUpload />` — they are not exported
- Try to import React hooks like `useFileUpload` — they are not exported
- Look for dropzone components — they are not exported
The source code contains reference components for demonstration, but they are **not available** as imports. Use them as examples to build your own UI.
1. Install the package
npm install @salesforce/ui-bundle-template-feature-react-file-upload
Dependencies are automatically installed:
- `@salesforce/ui-bundle` (API client)
- `@salesforce/platform-sdk` (data SDK; the old `@salesforce/sdk-data` name is dead — see the `experience-ui-bundle-salesforce-data-access` skill)
2. Understand the three upload patterns
Pattern A: Basic upload (no record linking)
Upload files to Salesforce and get back `contentBodyId` for each file. No ContentVersion record is created.
**When to use:**
- User wants to upload files first, then create/link them to a record later
- Building a multi-step form where the record doesn't exist yet
- Deferred record linking scenarios
import { upload } from "@salesforce/ui-bundle-template-feature-react-file-upload";
const results = await upload({
files: [file1, file2],
onProgress: (progress) => {
console.log(`${progress.fileName}: ${progress.status} - ${progress.progress}%`);
},
});
// results[0].contentBodyId: "069..." (always available)
// results[0].contentVersionId: undefined (no record linked)Pattern B: Upload with immediate record linking
Upload files and immediately link them to an existing Salesforce record by creating ContentVersion records.
**When to use:**
- Record already exists (Account, Opportunity, Case, etc.)
- User wants files immediately attached to the record
- Direct upload-and-attach scenarios
import { upload } from "@salesforce/ui-bundle-template-feature-react-file-upload";
const results = await upload({
files: [file1, file2],
recordId: "001xx000000yyyy", // Existing record ID
onProgress: (progress) => {
console.log(`${progress.fileName}: ${progress.status} - ${progress.progress}%`);
},
});
// results[0].contentBodyId: "069..." (always available)
// results[0].contentVersionId: "068..." (linked to record)Pattern C: Deferred record linking (record creation flow)
Upload files without a record, then link them after the record is created.
**When to use:**
- Building a "create record with attachments" form
- Record doesn't exist until form submission
- Need to upload files before knowing the final record ID
import {
upload,
createContentVersion,
} from "@salesforce/ui-bundle-template-feature-react-file-upload";
// Step 1: Upload files (no recordId)
const uploadResults = await upload({
files: [file1, file2],
onProgress: (progress) => console.log(progress),
});
// Step 2: Create the record
const newRecordId = await createRecord(formData);
// Step 3: Link uploaded files to the new record
for (const file of uploadResults) {
const contentVersionId = await createContentVersion(
new File([""], file.fileName),
file.contentBodyId,
newRecordId,
);
}3. Build your custom UI
The package provides the backend — you build the frontend. Here's a minimal example:
import {
upload,
type FileUploadProgress,
} from "@salesforce/ui-bundle-template-feature-react-file-upload";
import { useState } from "react";
function CustomFileUpload({ recordId }: { recordId?: string }) {
const [progress, setProgress] = useState<Map<string, FileUploadProgress>>(new Map());
const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {
const files = Array.from(event.target.files || []);
await upload({
files,
recordId,
onProgress: (fileProgress) => {
setProgress((prev) => new Map(prev).set(fileProgress.fileName, fileProgress));
},
});
};
return (
<div>
<input type="file" multiple onChange={handleFileSelect} />
{Array.from(progress.entries()).map(([fileName, fileProgress]) => (
<div key={fileName}>
{fileName}: {fileProgress.status} - {fileProgress.progress}%
{fileProgress.error && <span>Error: {fileProgress.error}</span>}
</div>
))}
</div>
);
}4. Track upload progress
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)
Read more
name: experience-ui-bundle-file-upload-generate
description: "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."
metadata:
version: "1.0"
relatedSkills:
- "experience-ui-bundle-salesforce-data-access"
cliTools:
- tool: ["npm"]
semver: ">=7.0.0"File Upload API (workflow)
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.
CRITICAL: This is an API-only package
The package exports **programmatic APIs**, not React components or hooks. You will:
- Use the `upload()` function to handle file uploads with progress tracking
- Build your own custom UI (file input, dropzone, progress bars, etc.)
- Track upload progress through the `onProgress` callback
**Do NOT:**
- Expect pre-built components like `<FileUpload />` — they are not exported
- Try to import React hooks like `useFileUpload` — they are not exported
- Look for dropzone components — they are not exported
The source code contains reference components for demonstration, but they are **not available** as imports. Use them as examples to build your own UI.
1. Install the package
npm install @salesforce/ui-bundle-template-feature-react-file-upload
Dependencies are automatically installed:
- `@salesforce/ui-bundle` (API client)
- `@salesforce/platform-sdk` (data SDK; the old `@salesforce/sdk-data` name is dead — see the `experience-ui-bundle-salesforce-data-access` skill)
2. Understand the three upload patterns
Pattern A: Basic upload (no record linking)
Upload files to Salesforce and get back `contentBodyId` for each file. No ContentVersion record is created.
**When to use:**
- User wants to upload files first, then create/link them to a record later
- Building a multi-step form where the record doesn't exist yet
- Deferred record linking scenarios
import { upload } from "@salesforce/ui-bundle-template-feature-react-file-upload";
const results = await upload({
files: [file1, file2],
onProgress: (progress) => {
console.log(`${progress.fileName}: ${progress.status} - ${progress.progress}%`);
},
});
// results[0].contentBodyId: "069..." (always available)
// results[0].contentVersionId: undefined (no record linked)Pattern B: Upload with immediate record linking
Upload files and immediately link them to an existing Salesforce record by creating ContentVersion records.
**When to use:**
- Record already exists (Account, Opportunity, Case, etc.)
- User wants files immediately attached to the record
- Direct upload-and-attach scenarios
import { upload } from "@salesforce/ui-bundle-template-feature-react-file-upload";
const results = await upload({
files: [file1, file2],
recordId: "001xx000000yyyy", // Existing record ID
onProgress: (progress) => {
console.log(`${progress.fileName}: ${progress.status} - ${progress.progress}%`);
},
});
// results[0].contentBodyId: "069..." (always available)
// results[0].contentVersionId: "068..." (linked to record)Pattern C: Deferred record linking (record creation flow)
Upload files without a record, then link them after the record is created.
**When to use:**
- Building a "create record with attachments" form
- Record doesn't exist until form submission
- Need to upload files before knowing the final record ID
import {
upload,
createContentVersion,
} from "@salesforce/ui-bundle-template-feature-react-file-upload";
// Step 1: Upload files (no recordId)
const uploadResults = await upload({
files: [file1, file2],
onProgress: (progress) => console.log(progress),
});
// Step 2: Create the record
const newRecordId = await createRecord(formData);
// Step 3: Link uploaded files to the new record
for (const file of uploadResults) {
const contentVersionId = await createContentVersion(
new File([""], file.fileName),
file.contentBodyId,
newRecordId,
);
}3. Build your custom UI
The package provides the backend — you build the frontend. Here's a minimal example:
import {
upload,
type FileUploadProgress,
} from "@salesforce/ui-bundle-template-feature-react-file-upload";
import { useState } from "react";
function CustomFileUpload({ recordId }: { recordId?: string }) {
const [progress, setProgress] = useState<Map<string, FileUploadProgress>>(new Map());
const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {
const files = Array.from(event.target.files || []);
await upload({
files,
recordId,
onProgress: (fileProgress) => {
setProgress((prev) => new Map(prev).set(fileProgress.fileName, fileProgress));
},
});
};
return (
<div>
<input type="file" multiple onChange={handleFileSelect} />
{Array.from(progress.entries()).map(([fileName, fileProgress]) => (
<div key={fileName}>
{fileName}: {fileProgress.status} - {fileProgress.progress}%
{fileProgress.error && <span>Error: {fileProgress.error}</span>}
</div>
))}
</div>
);
}4. Track upload progress
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)
This repository provides a curated collection of Salesforce agent skills for building applications.
Repo: forcedotcom/sf-skills
Other skills on sf-skills.
- /agentforce-generate
Build, modify, optimize, debug, and deploy agents with Agentforce Agent Script. TRIGGER when: user creates, modifies, optimizes, or asks about .agent files or aiAuthoringBundle metadata; changes agent behavior, responses, or conversation logic; designs agent actions, tools,
Open skill - /agentforce-observe
Analyze production Agentforce agent behavior using session traces and Data Cloud. TRIGGER when: user queries STDM session data or Data Cloud trace records; investigates production agent failures, regressions, or performance issues; asks about session traces, conversation logs,
Open skill - /agentforce-test
Write, run, and analyze structured test suites for Agentforce agents — functional AND security. TRIGGER when: user writes or modifies test spec YAML (AiEvaluationDefinition); runs sf agent test create, run, run-eval, or results commands; asks about test coverage strategy, metric
Open skill - /automation-flow-generate
Generate Salesforce Flows using the MCP tool execute_metadata_action. Use when the user asks to create, build, or generate a flow — including Screen, Autolaunched, Record-Triggered (before/after-save), Scheduled. Also trigger for flow-like requests such as \"when a record is
Open skill - /dx-code-analyzer-configure
Set up, configure, and troubleshoot Salesforce Code Analyzer for any project. Handles installation, prerequisite checks, diagnosing broken setups, creating and editing code-analyzer.yml overrides, engine-specific settings, ignore patterns, severity overrides, and CI/CD pipeline
Open skill - /dx-code-analyzer-custom-rule-create
Create custom Code Analyzer rules for Regex (pattern matching), PMD (XPath/AST for Apex and metadata XML), and ESLint (LWC/JavaScript/TypeScript). Use when users want to enforce coding standards, ban patterns, detect hardcoded values, govern metadata, or add rules not in the
Open skill

