LWCのボタンから検索結果をCSVで受け取る実装手順
Homeタブに置いたボタンを押すと検索画面が開き、絞り込んだ結果をCSVでダウンロードできるようになります。LWC側でファイルを作らずVisualforceに任せる理由を説明します。
データローダやレポートのエクスポートで足りるとき
取引先責任者を丸ごと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のままにしています。
#以降に書いた名前が、そのまま保存名になります。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へ上げています。
new Blob([data], {type: 'text/csv'})のようにtext/csvを指定すると、Lightning Web Securityの許可リストに無いMIMEタイプとしてブロックされます。許可されているのはapplication/octet-streamやtext/plainなどに限られるため、この記事のようにVisualforce側でCSVを生成・ダウンロードさせるほうが安全です。Homeタブへコンポーネントを配置する
Homeタブを編集する
「Home」タブを開き、右上の歯車アイコンから「ページを編集」を選びます。
コンポーネントを追加する
コンポーネント一覧から「LwcCSVファイルダウンロード」をドラッグして配置します。
保存して有効化する
「保存」のあと「有効化」を押し、公開範囲を選びます。
Homeタブのボタンを押すとCSVSearchPageが新しいタブで開きます。「CSV Search」で結果が表示されると「CSV Download」ボタンが現れ、押すとExtract_Contact.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.csvなので、保存名もアンダースコア付きになります。Salesforceの導入・運用についてご相談ください
導入前の検討から、お使いの環境の改修・運用、AIとの連携まで承ります。状況を伺ったうえで、進め方をご提案します。