Skip to main content

How to Export Data to CSV in Salesforce Lightning Web Components (LWC)

In plain words: Exporting data to CSV in LWC allows users to download records from custom datatables or Apex queries directly into a .csv spreadsheet using pure client-side JavaScript—without needing third-party libraries or extra server round-trips.

Exporting tabular data to CSV (Comma-Separated Values) is a frequent requirement in Salesforce business applications. Whether you are providing a quick report download on an Account page or letting users export custom dashboard metrics, handling CSV creation inside Lightning Web Components provides a seamless, high-speed user experience.

Why Handle CSV Export on the Client Side?

  • Zero Server Load: Generates the entire file in the user's browser, eliminating CPU and heap limit strain on Apex controllers.
  • Instant Downloads: Creates a downloadable file immediately with standard JavaScript Blob and URL.createObjectURL APIs.
  • Universal Format: CSV files seamlessly open in Excel, Google Sheets, or data analytics platforms.

1. Building the Component Template

The UI component contains a standard lightning-button to trigger the download workflow.

<!-- exportButton.html -->
<template>
  <lightning-card title="Export Records" icon-name="custom:custom63">
    <div class="slds-p-around_medium">
      <p class="slds-m-bottom_small">Click the button below to download the latest account list.</p>
      <lightning-button 
        variant="brand" 
        label="Export to CSV" 
        icon-name="utility:download" 
        onclick={handleExport}>
      </lightning-button>
    </div>
  </lightning-card>
</template>

2. Implementing the JavaScript CSV Converter and Downloader

The JavaScript controller transforms record objects into comma-separated lines, escapes special characters, builds a Blob, and triggers the browser download action.

// exportButton.js
import { LightningElement } from 'lwc';

export default class ExportButton extends LightningElement {
  // Sample data source (can also be populated via @wire or imperative Apex)
  records = [
    { Id: '001', Name: 'Acme Corp', Industry: 'Manufacturing', AnnualRevenue: 5000000 },
    { Id: '002', Name: 'Global Media, Inc.', Industry: 'Media & Tech', AnnualRevenue: 12500000 },
    { Id: '003', Name: 'Summit Health', Industry: 'Healthcare', AnnualRevenue: 3400000 }
  ];

  columnHeader = ['Id', 'Name', 'Industry', 'AnnualRevenue'];

  handleExport() {
    if (!this.records || !this.records.length) {
      return;
    }
    const csvContent = this.convertToCSV(this.records, this.columnHeader);
    this.downloadCSVFile(csvContent, 'Account_Export.csv');
  }

  convertToCSV(data, headers) {
    const csvRows = [];
    
    // Add header row
    csvRows.push(headers.join(','));

    // Format each record row
    data.forEach(record => {
      const values = headers.map(header => {
        let val = record[header] !== undefined && record[header] !== null ? String(record[header]) : '';
        // Escape quotes and wrap values containing commas or line breaks in double quotes
        if (val.includes(',') || val.includes('"') || val.includes('\n')) {
          val = `"${val.replace(/"/g, '""')}"`;
        }
        return val;
      });
      csvRows.push(values.join(','));
    });

    return csvRows.join('\r\n');
  }

  downloadCSVFile(csvData, fileName) {
    // Prefix UTF-8 BOM to guarantee proper character encoding in Microsoft Excel
    const blob = new Blob(['\uFEFF' + csvData], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
    
    const link = document.createElement('a');
    link.href = url;
    link.download = fileName;
    link.style.display = 'none';
    
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    
    URL.revokeObjectURL(url);
  }
}
Step-by-Step Execution Breakdown:
  • Map Data: Extract values row-by-row based on your defined column headers.
  • Escape Strings: Wrap strings with double quotes if they contain commas, newlines, or quotation marks to preserve CSV columns.
  • Create Blob: Convert the raw string into a standard CSV Blob object.
  • Trigger Virtual Link: Dynamically create and click an invisible <a> element to prompt the browser's save dialog.
Common Pitfall — Character Encoding & Excel: When CSV files contain accents, special symbols, or non-Latin characters, Excel can display corrupted text. Adding the UTF-8 Byte Order Mark (\uFEFF) to the beginning of your Blob prevents this formatting issue completely.

3. Exposing the Component in Lightning App Builder

To make the component available on Record Pages, App Pages, or Home Pages, configure your component XML configuration file.

<!-- exportButton.js-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>61.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__RecordPage</target>
        <target>lightning__AppPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
360 Card: CSV Export Best Practices
  • Browser Performance: Best suited for small to medium datasets (up to a few thousand records). For massive bulk extractions (50,000+ rows), use Bulk API 2.0 or asynchronous batch jobs.
  • Column Customization: Use dynamic column mapping to allow users to export only visible columns from a lightning-datatable.
  • Memory Cleanup: Always invoke URL.revokeObjectURL(url) to release browser memory immediately after the click event triggers.
Core Takeaway: Client-side CSV generation provides a fast, lightweight export experience in Salesforce without incurring governor limit penalties or writing custom server-side export services.