npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@salesforce/ui-bundle-template-feature-react-file-upload

v1.131.0

Published

File upload feature with a component to upload files to core

Readme

Feature: File Upload API

File upload API package that provides programmatic APIs for uploading files to Salesforce with progress tracking and ContentVersion integration. This package serves as a reference implementation with APIs that allow you to build your own custom UI.

Package Purpose

This package exposes APIs only - no components or hooks are exported. You can:

  • Use the upload() API to handle the complete upload flow
  • Build your own custom UI with full control over the user experience
  • Track upload progress for each file in real-time
  • Optionally create ContentVersion records linked to Salesforce records

The included components in the source code are for demonstration and testing purposes only.

Exports

API Functions

  • upload – Unified upload API that handles config, upload with progress tracking, and optionally creates ContentVersion records
  • createContentVersion – Manually create a ContentVersion record from a contentBodyId
  • getCurrentUserId – Get the current user's Salesforce ID

Types

  • UploadOptions – Configuration options for the upload function
  • FileUploadResult – Result object containing file info and IDs
  • FileUploadProgress – Progress callback data for tracking upload status
  • UploadStatus – Upload status enum: "pending" | "uploading" | "processing" | "success" | "error"

Usage Guide

Basic Upload with Progress Tracking

Upload files to Salesforce with real-time progress tracking for each file:

import { upload } from "@salesforce/ui-bundle-template-feature-react-file-upload";

async function handleUpload(files: File[]) {
  const results = await upload({
    files,
    onProgress: (progress) => {
      console.log(`${progress.fileName}: ${progress.status} - ${progress.progress}%`);
      // Update your UI with progress.status and progress.progress
    },
  });

  console.log("Upload complete:", results);
  // results[0].contentBodyId: "069..." (always available)
  // results[0].contentVersionId: undefined (no record linked)
}

Upload with Record Linking

Link uploaded files to a Salesforce record immediately by providing recordId:

import { upload } from "@salesforce/ui-bundle-template-feature-react-file-upload";

async function uploadToRecord(files: File[], recordId: string) {
  const results = await upload({
    files,
    recordId, // Links files to this record (Account, Opportunity, etc.)
    onProgress: (progress) => {
      // Track progress: pending → uploading → processing → success
      updateUI(progress.fileName, progress.status, progress.progress);
    },
  });

  // Both contentBodyId and contentVersionId are available
  console.log("Uploaded to record:", results);
}

Deferred Record Linking (Record Creation Pattern)

When creating a new record: Upload files first without recordId, then link them after the record is created:

import {
  upload,
  createContentVersion,
} from "@salesforce/ui-bundle-template-feature-react-file-upload";

async function createRecordWithFiles(formData: any, files: File[]) {
  // Step 1: Upload files (no recordId yet)
  const uploadResults = await upload({
    files,
    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,
    );
    console.log("ContentVersion created:", contentVersionId);
  }
}

Cancel Upload

Use an AbortController to cancel uploads:

import { upload } from "@salesforce/ui-bundle-template-feature-react-file-upload";

function UploadComponent() {
  const abortController = new AbortController();

  const handleUpload = async (files: File[]) => {
    try {
      await upload({
        files,
        signal: abortController.signal,
        onProgress: (progress) => console.log(progress),
      });
    } catch (error) {
      console.error("Upload failed or cancelled:", error);
    }
  };

  const cancelUpload = () => {
    abortController.abort();
  };

  return (
    <div>
      <button onClick={() => handleUpload(selectedFiles)}>Upload</button>
      <button onClick={cancelUpload}>Cancel</button>
    </div>
  );
}

API Reference

upload(options)

Unified upload API that handles the complete upload flow with progress tracking.

Parameters:

interface UploadOptions {
  /** Files to upload */
  files: File[];

  /**
   * Record ID to link files to (FirstPublishLocationId).
   * - If provided: Creates ContentVersion and links to this record
   * - If null/undefined: Only uploads file, returns contentBodyId only
   */
  recordId?: string | null;

  /** Callback for upload progress of each file */
  onProgress?: (progress: FileUploadProgress) => void;

  /** Optional abort signal to cancel all uploads */
  signal?: AbortSignal;
}

interface FileUploadProgress {
  fileName: string;
  status: "pending" | "uploading" | "processing" | "success" | "error";
  progress: number; // 0-100 for uploading, 0 for other states
  error?: string;
}

Returns: Promise<FileUploadResult[]>

interface FileUploadResult {
  fileName: string;
  size: number;
  contentBodyId: string; // Always available
  contentVersionId?: string; // Only if recordId was provided
}

createContentVersion(file, contentBodyId, recordId)

Manually create a ContentVersion record from a previously uploaded file.

Parameters:

  • file (File): The file object (used for metadata like name)
  • contentBodyId (string): The ContentBody ID from a previous upload
  • recordId (string): The record ID for FirstPublishLocationId

Returns: Promise<string | undefined> - The ContentVersion ID if successful

const contentVersionId = await createContentVersion(file, "069xx000000xxxx", "001xx000000yyyy");

getCurrentUserId()

Get the current user's Salesforce ID.

Returns: Promise<string> - The current user ID

const userId = await getCurrentUserId();

Building Your Own UI

This package provides the backend APIs - you can build any UI you want. Here's a basic 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>
  );
}

Agent/Vibe Integration Guide

When building file upload functionality with an AI agent like Vibe, follow this pattern:

1. Ask User for Record Context

Agent: "Do you want to link uploaded files to a specific record, or upload them first and link later?"

Options:
A) Link to existing record (provide recordId)
B) Upload only (link later with createContentVersion)
C) Link to current user

2. Implement Based on Response

Option A: Link to existing record

await upload({ files, recordId: "001xx000000yyyy" });

Option B: Upload only, link later

const results = await upload({ files }); // No recordId
// Later: await createContentVersion(file, results[0].contentBodyId, newRecordId);

Option C: Link to current user

const userId = await getCurrentUserId();
await upload({ files, recordId: userId });

3. Track Progress in Your UI

Always provide progress feedback to users:

onProgress: (progress) => {
  // Update your UI based on:
  // - progress.fileName
  // - progress.status (pending, uploading, processing, success, error)
  // - progress.progress (0-100)
  // - progress.error (if status is 'error')
};

Skills

https://docs.cline.bot/features/skills

The sample includes a skill to show how a feature can bundle an on-demand workflow.

Copy the skills/implementing-file-upload/ folder into .cline/skills/ (Cline) or .cursor/skills/ (Cursor) to try it, or use it as a template for your own skills.

Dependencies

  • @salesforce/ui-bundle – For API client and Salesforce integration
  • @salesforce/sdk-data – For data SDK integration

Reference Implementation

This package includes a reference implementation with UI components for demonstration purposes. The components are located in src/features/fileupload/ and include:

  • FileUpload component with drop zone and progress dialog
  • useFileUpload hook for custom implementations
  • Test pages showing various usage patterns

These are not exported from the package but can be viewed as examples of how to build your own UI using the APIs.

Testing

Test the reference implementation locally:

npx nx dev @salesforce/ui-bundle-template-feature-react-file-upload

Open the app and navigate to the test pages to see the APIs in action.