LWC

LWCのボタンから検索結果をCSVで受け取る実装手順

Homeタブに置いたボタンを押すと検索画面が開き、絞り込んだ結果をCSVでダウンロードできるようになります。LWC側でファイルを作らずVisualforceに任せる理由を説明します。

2021.06.04

データローダやレポートのエクスポートで足りるとき

取引先責任者を丸ごとCSVで持ち出すだけなら、データローダのエクスポートか、レポートのCSVエクスポートで足ります。レポートは画面表示こそ最大2,000行ですが、CSV形式のエクスポートに件数の上限はありません。

それでも作り込むのは、検索条件を「作成日の新しい順で上位4件」のように固定したい、Homeタブに置いて誰でも迷わず押せるようにしたい、出力項目を4つだけに絞りたい、といった事情があるときです。条件を固定しない全件エクスポートなら、まずデータローダかレポートを検討してください。

検索とダウンロードを処理するApexクラス

LWCのボタンが検索用のVisualforceページを開き、そこからダウンロード用ページへ進む3段構成です。CSVの生成はVisualforceのcontentTypeが担い、LWCはボタンと画面遷移だけを受け持ちます。

CSVDownloadController.cls

public inherited sharing class CSVDownloadController {
    public List<Contact> contacts {get; set;}
    public CSVDownloadController() {
        this.contacts = new List<Contact>();
    }
    public void doSearchClick() {
        this.contacts = [SELECT Id, LastName, FirstName, Phone, MailingState FROM Contact ORDER BY CreatedDate DESC LIMIT 4];
    }
    public PageReference doDownloadClick() {
        return Page.CSVDownloadPage.setRedirect(false);
    }
}

取引先責任者を検索し、ダウンロードページへのPageReferenceを返します。SOQLはループの外で1回だけ発行しています。

LIMIT 4は記事用の固定値です。実際に使うときは項目や設定値から件数を決めてください。

検索結果を表示するVisualforceページ

CSVSearchPage.page

<apex:page controller="CSVDownloadController" apiVersion="67.0" title="CSVSearchPage" showHeader="true" sidebar="false" id="page">
    <apex:form id="form">
        <apex:pageBlock id="block">
            <apex:pageBlockButtons>
                <apex:commandButton value="CSV Search" action="{!doSearchClick}" reRender="form" />
                <apex:commandButton value="CSV Download" action="{!doDownloadClick}" rendered="{!contacts.size > 0}" />
            </apex:pageBlockButtons>
            <apex:pageBlockTable value="{!contacts}" var="item">
                <apex:column headerValue="{!$ObjectType.Contact.Fields.LastName.Label}">
                    <apex:outputText value="{!item.LastName}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Contact.Fields.FirstName.Label}">
                    <apex:outputText value="{!item.FirstName}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Contact.Fields.Phone.Label}">
                    <apex:outputText value="{!item.Phone}" />
                </apex:column>
                <apex:column headerValue="{!$ObjectType.Contact.Fields.MailingState.Label}">
                    <apex:outputText value="{!item.MailingState}" />
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlock>
    </apex:form>
</apex:page>

検索ボタンで一覧を表示し、1件以上あるときだけダウンロードボタンを出します。apiVersionを67.0で明示しています。

CSVを生成してダウンロードさせるVisualforceページ

CSVDownloadPage.page

<apex:page controller="CSVDownloadController" apiVersion="67.0" cache="false" contentType="text/csv#Extract_Contact.csv" language="en-US">
"LastName","FirstName","Phone","MailingState"
    <apex:repeat value="{!contacts}" var="item">
        "{!item.LastName}","{!item.FirstName}","{!item.Phone}","{!item.MailingState}"
    </apex:repeat>
</apex:page>

contentTypeを「MIMEタイプ#ファイル名」の形にすると、ダウンロード時のファイル名を指定できます。

contentTypeをMIMEタイプの後ろに#とファイル名を続ける書き方は、Visualforceのリファレンスに載っている正式な指定方法です。cacheのデフォルトはfalseで、検索結果は毎回変わるためここでもfalseのままにしています。

ファイル保存ダイアログ。ファイル名にExtract_Contact、種類にCSVファイルが入っている
ダウンロード時のファイル名です。contentTypeの#以降に書いた名前が、そのまま保存名になります。
テキストエディタで開いたCSV。1行目が見出しで、2行目以降に姓・名・電話番号・都道府県が並ぶ
落ちてきたCSVの中身です。1行目が見出しで、各値がダブルクォーテーションで囲まれています。
同じCSVの中身を改行記号と終端記号を表示した状態で開いたところ
改行とEOFを表示した状態です。行の区切りと終端が意図どおりか、ここで確かめられます。
このページはBOMなしのUTF-8で出力されます。姓名に日本語が入っていると、Excelでダブルクリックして開いたときに文字化けすることがあります。日本語を含むCSVをExcelで確実に開きたいときは、Excelのテキストインポートウィザードで文字コードをUTF-8に指定して読み込んでください。

LWCから検索ページを呼び出すボタン

lwcCSVDownload.html

<template>
    <lightning-card title="LwcCSVファイルダウンロード" icon-name="custom:custom15">
        <div class="slds-p-horizontal_medium slds-p-vertical_small">
            <lightning-button
                variant="brand"
                label="CSVファイルダウンロード"
                onclick={handleOutput}>
            </lightning-button>
        </div>
    </lightning-card>
</template>

Homeタブに置くカードとボタンです。ボタンを押すと検索ページを新しいタブで開きます。

lwcCSVDownload.js

import { LightningElement } from 'lwc';
export default class LwcCSVDownload extends LightningElement {
    handleOutput() {
        window.open('/apex/CSVSearchPage', '_blank');
    }
}

検索用Visualforceページを新しいタブで開くだけの処理です。CSVの生成はコンポーネント側で行いません。

lwcCSVDownload.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>67.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

apiVersionを51.0から67.0へ引き上げています。Homeページ用のコンポーネントとして公開する設定です。

当時の記事のapiVersionは51.0でした。2026年9月時点の最新はSummer '26のAPI 67.0なので、コードはすべて67.0へ上げています。

CSVをLWCの中だけで完結させたくなりますが、new Blob([data], {type: 'text/csv'})のようにtext/csvを指定すると、Lightning Web Securityの許可リストに無いMIMEタイプとしてブロックされます。許可されているのはapplication/octet-streamやtext/plainなどに限られるため、この記事のようにVisualforce側でCSVを生成・ダウンロードさせるほうが安全です。

Homeタブへコンポーネントを配置する

  1. Homeタブを編集する

    「Home」タブを開き、右上の歯車アイコンから「ページを編集」を選びます。

  2. コンポーネントを追加する

    コンポーネント一覧から「LwcCSVファイルダウンロード」をドラッグして配置します。

  3. 保存して有効化する

    「保存」のあと「有効化」を押し、公開範囲を選びます。

Homeタブのボタンを押すとCSVSearchPageが新しいタブで開きます。「CSV Search」で結果が表示されると「CSV Download」ボタンが現れ、押すとExtract_Contact.csvという名前でファイルがダウンロードされます。

検索画面。CSV Searchボタンだけがあり、姓・名・電話・都道府県の見出しの下は空
開いた直後の検索画面です。まだ0件なので「CSV Download」ボタンは出ていません。
検索後の画面。取引先責任者が4件表示され、CSV Downloadボタンが増えている
「CSV Search」を押した後です。1件以上あると「CSV Download」ボタンが現れます。件数が4件なのはLIMIT 4のためです。
同じ検索結果画面。姓に鈴木・山田、都道府県に神奈川県・東京都が入っている
日本語のテストデータで検索した場合です。赤枠の4件が、そのままCSVの中身になります。

ここで間違えやすい

間違い何が起きるか
ダウンロードページのcacheをtrueにする検索条件を変えても古いCSVが落ちてくることがあります
LWCの中でBlobにtext/csvを指定するLightning Web Securityにブロックされ、ファイルが生成されません
大量件数を一度に検索するビューステートの上限に達し、ページが表示できなくなります

大量件数を出力するとき

この構成は数件から数十件の「決まった条件での取り出し」向きです。件数が増えると、Apex同期処理のヒープサイズ上限6MBや、Visualforceのビューステート上限170KBに近づきます。SOQLも1クエリで返せるのは最大50,000行までです。数千件を超える全件エクスポートには、この仕組みを広げるのではなく、データローダかBulk APIを使ってください。

確認した環境

  • 2026年9月 / Salesforce Summer '26(APIバージョン67.0)時点の公式ドキュメントで、contentTypeの書き方、Lightning Web SecurityのMIMEタイプ許可リスト、ヒープサイズとビューステートの上限を確認しています
  • コードはAPIバージョン67.0で書いています

まとめ

  • 条件を固定しない全件エクスポートなら、データローダかレポートのCSVエクスポートで足ります
  • この構成はLWCがボタンと画面遷移を受け持ち、CSVの生成はVisualforceのcontentTypeに任せています
  • LWCでBlobにtext/csvを指定するとLightning Web Securityにブロックされるため、その場でファイルを作る実装は避けます
  • .js-meta.xmlのapiVersionは51.0から67.0へ引き上げています
  • 大量件数の出力には向きません。ヒープサイズ・ビューステート・SOQLの行数上限に注意し、データローダかBulk APIへ切り替えてください

参考:当時の画面

記事を最初に書いた当時の画面です。いまの手順と違うところは、各画像の説明に書いています。

ファイル保存ダイアログ。ファイル名がExtract Contactと空白区切りになっている
記事のコードはExtract_Contact.csvなので、保存名もアンダースコア付きになります。
Lightningアプリケーションビルダーの編集画面。左のカスタム一覧からコンポーネントをキャンバスへドラッグしている
左の「カスタム」からコンポーネントを右のキャンバスへ運び、右上の「保存」「有効化」を押します。

Salesforceの導入・運用についてご相談ください

導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。