WP 301 Redirects

In the Salesforce ecosystem, working with files is essential for many business scenarios. Whether it’s invoices, marketing assets, or customer records, files play a critical role in enhancing user productivity. With the introduction of Lightning Web Components (LWC), developers can create dynamic and responsive UI components to deliver a better user experience. Querying files and displaying them using an LWC component enables a seamless integration of such digital assets within the Salesforce UI, and this article provides a comprehensive guide on how to achieve that.

Understanding Salesforce Files and ContentDocument

Before diving into development, it’s essential to understand how Salesforce stores files. Files in Salesforce are stored as ContentDocument objects. These documents can have multiple ContentVersion records that represent different versions of the same file. Files are linked to records using ContentDocumentLink.

Here’s a quick overview of the relationships among these objects:

  • ContentDocument: Represents a document that has been uploaded to the library.
  • ContentVersion: Represents a specific version of a document.
  • ContentDocumentLink: Links documents to standard or custom object records.

To query files associated with a specific record, the starting point is ContentDocumentLink, which links the file to the record through the LinkedEntityId.

Querying Files in Apex

Since LWC cannot directly perform SOQL queries, you’ll need an Apex controller to retrieve the data. Below is a sample Apex method that queries files associated with a record:

public with sharing class FileController {
    @AuraEnabled(cacheable=true)
    public static List<ContentVersion> fetchFiles(Id recordId) {
        List<ContentDocumentLink> links = [
            SELECT ContentDocumentId
            FROM ContentDocumentLink
            WHERE LinkedEntityId = :recordId
        ];

        Set<Id> documentIds = new Set<Id>();
        for(ContentDocumentLink link : links) {
            documentIds.add(link.ContentDocumentId);
        }

        return [
            SELECT Id, Title, VersionData, ContentDocumentId, FileType
            FROM ContentVersion
            WHERE ContentDocumentId IN :documentIds
            AND IsLatest = true
        ];
    }
}

The above method retrieves the latest version of each file associated with a specific record.

Creating the LWC Component

Once the Apex controller is ready, it’s time to create the frontend using LWC. Below is a basic lightning web component that will display the fetched file data.

fileDisplay.html

<template>
    <lightning-card title="Attached Files">
        <template if:true={files}>
            <template for:each={files} for:item="file">
                <div key={file.Id} class="slds-box slds-box_xx-small">
                    <p><b>{file.Title}</b></p>
                    <p>Type: {file.FileType}</p>
                    <a href={file.downloadUrl} target="_blank">Download</a>
                </div>
            </template>
        </template>
        <template if:true={error}>
            <c-error-panel message={error}></c-error-panel>
        </template>
    </lightning-card>
</template>

fileDisplay.js

import { LightningElement, api, wire } from 'lwc';
import fetchFiles from '@salesforce/apex/FileController.fetchFiles';

export default class FileDisplay extends LightningElement {
    @api recordId;
    files;
    error;

    @wire(fetchFiles, { recordId: '$recordId' })
    wiredFiles({ data, error }) {
        if (data) {
            this.files = data.map(file => {
                return {
                    Id: file.Id,
                    Title: file.Title,
                    FileType: file.FileType,
                    downloadUrl: '/sfc/servlet.shepherd/version/download/' + file.Id
                };
            });
            this.error = undefined;
        } else if (error) {
            this.error = error.body.message;
            this.files = undefined;
        }
    }
}

This component uses Lightning Design System (SLDS) classes for styling and displays basic file information such as title, type, and a download link. The file download URL is constructed using the ContentVersion Id.

Deploying and Using the Component

Once the component is created, you can expose it in the record pages using the targetConfigs in the component’s meta.xml file:

fileDisplay.js-meta.xml

<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <objects>
                <object>Account</object>
                <object>Contact</object>
                <object>CustomObject__c</object>
            </objects>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

With the component properly added to a record page via the Lightning App Builder, users will see the attached files on the record instantly.

Enhancing User Experience

There are several ways to enhance the component:

  • Thumbnail Preview: Utilize the ContentThumbnail API for image previews.
  • Drag and Drop Upload: Include components that allow file uploading directly.
  • Preview in Modal: Integrate Lightning Modal or NavigationMixin to preview files without downloading.

These enhancements can turn a basic component into a powerful document management tool inside Salesforce.

Security and Permission Considerations

Ensure that users have access to the files via sharing settings and that they are assigned appropriate permissions, such as:

  • View Content in Libraries
  • Read access to ContentVersion and ContentDocument
  • Record-level access to LinkedEntityId

Without proper access, files may fail to show or download as expected.

Conclusion

Displaying files using an LWC component not only improves user engagement but also consolidates essential digital content in one place. By leveraging Apex to query file data and Lightning Web Components to render it beautifully on screen, Salesforce administrators and developers can deliver a seamless, unified experience.

Frequently Asked Questions (FAQ)

  • Q: Can I upload new files using the same LWC component?
    A: You’d need to add a file upload module using <lightning-file-upload> component to handle uploads alongside file displays.
  • Q: Why am I seeing a “URL no longer exists” message when clicking on the download link?
    A: This usually happens if users don’t have access to the file or the ContentVersion Id used for constructing the download URL is invalid or outdated.
  • Q: How can I show only image files in the component?
    A: You can filter the returned list in Apex or LWC based on FileType – for example, show only those where FileType = 'PNG' || 'JPG'.
  • Q: How do I get file URLs that can be embedded inline?
    A: Use the renditionViewUrl from ContentVersion or FilePreview APIs depending on the use case.
  • Q: Is it possible to paginate the file results?
    A: Yes, you can implement pagination in Apex by using OFFSET and LIMIT