LWRサイトを構築中なら、CPEよりもSpring ’26で一般公開となったExperiencePropertyTypeBundlesをおすすめします!
ExperiencePropertyTypeBundlesを使った実装方法は以下の記事をご覧ください。
LWCでExperience Cloud用コンポーネントを作成する際、js-meta.xml でプロパティを定義すると、Experience Builder(設定画面)上に自動的に入力欄が表示されます。
しかし、標準のテキストボックスやチェックボックスだけでは、「直感的ではない」「設定ミスが起きやすい」と感じることはありませんか?
今回は、架空の紅茶ECサイト「The Royal Brew」のキャンペーンバナーを作成しながら、この設定画面自体をLWCで作る技術、Custom Property Editor (CPE) について解説します。
- 基礎編: バナーの画像の「不透明度」をスライダーで直感的に調整する。
- 応用編: バナーの「リンク先カテゴリ」をSalesforceの商品データから動的に選択する。
この2段階で、アドミンにとって優しい設定画面(UX for Admins)を構築していきましょう。

今回の記事で作成したコンポーネントの全ソースコードをGitHubで公開しています。 ぜひ Clone して、あなたの組織で動かしてみてください。
シナリオ: 「キャンペーンバナー」の要件
作成するのは、トップページに配置する c-campaign-banner です。 運用担当者からは、以下の要望が出ています。
- 「文字が読みやすいように、画像の明るさ(不透明度)を微調整したい。でも数値入力は面倒。」
- 「クリックした時の遷移先カテゴリを選びたい。手入力だとIDを間違えるので、リストから選びたい。」
これらをCPEで解決します。

【基礎編】スライダーで直感的な数値入力を実装する
まずは要望1の解決です。標準の数値入力欄を、0%〜100%のスライダーに置き換えます。
エディタ用コンポーネントの作成 (c-opacity-slider-editor)
設定画面のUIとなるコンポーネントです。 CPEとして動作するためには、@api value で値を受け取り、変更時に valuechange イベントを発火する必要があります。
HTML (opacitySliderEditor.html)
<template>
<div class="slds-p-around_x-small">
<lightning-slider
label={label}
value={value}
min="0"
max="100"
step="10"
onchange={handleChange}>
</lightning-slider>
<div class="slds-text-body_small slds-text-color_weak slds-m-top_xx-small">
現在の不透明度: {value}%
</div>
</div>
</template>
JavaScript (opacitySliderEditor.js)
import { LightningElement, api } from 'lwc';
export default class OpacitySliderEditor extends LightningElement {
// js-meta.xml で定義されたプロパティの現在値が自動的に渡されます
@api value;
// js-meta.xml で定義されたラベルが渡されます
@api label;
/**
* スライダーの値が変更された時の処理
* @param {Event} event
*/
handleChange(event) {
const newValue = event.detail.value;
// 値の変更をExperience Builderに通知するカスタムイベントを発火
// イベント名は必ず 'valuechange' である必要があります
this.dispatchEvent(new CustomEvent('valuechange', {
detail: {
value: newValue
}
}));
}
}
XML (opacitySliderEditor.js-meta.xml)
エディタ自体は画面に配置しないため、isExposed は false です。
これで、「不透明度」の設定用パーツが完成しました。
【応用編】Apex連携で動的な選択リストを作成する
次に要望2の解決です。 標準の設定画面では、選択肢(プルダウン)を作るには js-meta.xml に固定値を書く必要があります。しかし、商品カテゴリが増減するたびにコードを修正するのは非効率です。
そこで、Salesforce組織に登録されている商品カテゴリをApexで取得し、CPE上の選択肢として表示させます。
Apexコントローラー (CpeDynamicController)
Product2オブジェクトの Family 項目からピックリスト値を取得します。
/**
* @description LWRサイトのCustom Property Editor (CPE) 用のコントローラークラス
* Experience Builderの設定画面に動的なデータを提供します。
*/
public with sharing class CpeDynamicController {
/**
* @description Product2オブジェクトのFamily(商品ファミリ)ピックリスト値を取得します。
* LWCのcomboboxで使用できる形式(label, value)で返却します。
* @return List<Map<String, String>> ラベルとAPI参照名を含むマップのリスト
*/
@AuraEnabled(cacheable=true)
public static List<Map<String, String>> getProductFamilies() {
List<Map<String, String>> options = new List<Map<String, String>>();
try {
// Product2オブジェクトのFamily項目の定義を取得
Schema.DescribeFieldResult fieldResult = Product2.Family.getDescribe();
List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
// ピックリスト値をループしてリストに追加
for(Schema.PicklistEntry entry : ple) {
if(entry.isActive()) {
Map<String, String> option = new Map<String, String>();
option.put('label', entry.getLabel());
option.put('value', entry.getValue());
options.add(option);
}
}
} catch (Exception e) {
System.debug('Error fetching product families: ' + e.getMessage());
}
return options;
}
}
エディタ用コンポーネントの作成 (c-product-family-selector)
Apexから取得した値を lightning-combobox に渡します。
HTML (productFamilySelector.html)
<template>
<div class="slds-p-around_x-small">
<template if:true={options}>
<lightning-combobox
name="familySelector"
label={label}
value={value}
placeholder="カテゴリを選択してください"
options={options}
onchange={handleChange}>
</lightning-combobox>
</template>
<template if:true={error}>
<div class="slds-text-color_error slds-m-top_x-small">
データの取得に失敗しました。
</div>
</template>
</div>
</template>
JavaScript (productFamilySelector.js)
import { LightningElement, api, wire } from 'lwc';
import getProductFamilies from '@salesforce/apex/CpeDynamicController.getProductFamilies';
export default class ProductFamilySelector extends LightningElement {
@api value;
@api label;
options;
error;
// Apexからカテゴリ一覧を取得
@wire(getProductFamilies)
wiredProductFamilies({ error, data }) {
if (data) {
this.options = data;
this.error = undefined;
} else if (error) {
this.error = error;
}
}
handleChange(event) {
// 選択されたカテゴリ名をBuilderに通知
this.dispatchEvent(new CustomEvent('valuechange', {
detail: { value: event.detail.value }
}));
}
}
XML (productFamilySelector.js-meta.xml)
エディタ自体は画面に配置しないため、isExposed は false です。
これで、「商品カテゴリ選択」の設定用パーツが完成しました。
【完成】メインコンポーネントの実装
最後に、作成した2つのエディタコンポーネントを、メインの c-campaign-banner に適用し、実際の表示ロジックを作成します。
これにより、Experience Builderで設定した「不透明度」と「カテゴリ」が、実際にサイト上のバナーに反映されるようになります。
メタデータ設定 (campaignBanner.js-meta.xml)
ここで editor 属性を使用し、標準の入力欄を先ほど作成したCPE(カスタムエディタ)に置き換えます。
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>65.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>The Royal Brew キャンペーンバナー</masterLabel>
<targets>
<target>lightningCommunity__Page</target>
<target>lightningCommunity__Default</target>
</targets>
<targetConfigs>
<targetConfig targets="lightningCommunity__Default">
<property
name="overlayOpacity"
type="Integer"
label="オーバーレイ不透明度"
default="50"
editor="c/opacitySliderEditor"
/>
<property
name="targetCategory"
type="String"
label="リンク先カテゴリ"
editor="c/productFamilySelector"
/>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
UIの実装 (campaignBanner.html)
設定値を受け取り、スタイルとリンクを動的に生成します。
<template>
<div class="banner-container slds-is-relative slds-box slds-box_x-small slds-m-bottom_medium">
<img src="https://images.unsplash.com/photo-1594631252845-29fc4cc8cde9?q=80&w=1000&auto=format&fit=crop"
class="banner-image slds-is-absolute"
alt="Campaign Background"
style="width: 100%; height: 100%; object-fit: cover;"
>
<div class="overlay slds-is-absolute" style={overlayStyle}></div>
<div class="content slds-is-relative slds-p-around_large slds-text-align_center">
<h2 class="slds-text-heading_large slds-m-bottom_medium slds-text-color_inverse">
Seasonal Selection
</h2>
<p class="slds-text-body_regular slds-m-bottom_medium slds-text-color_inverse">
厳選された茶葉で、最高のティータイムを。
</p>
<lightning-button
variant="brand"
label="商品を見る"
onclick={handleNavigate}
class="slds-m-top_small">
</lightning-button>
</div>
</div>
</template>
ロジックの実装 (campaignBanner.js)
CPEから渡された値は、通常の @api プロパティとして受け取ります。
import { LightningElement, api } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
/**
* CPE (Custom Property Editor) で設定された値を利用するバナーコンポーネント
*/
export default class CampaignBanner extends NavigationMixin(LightningElement) {
/**
* オーバーレイの不透明度 (0-100)
* c/opacitySliderEditor によって設定されます
*/
@api overlayOpacity = 50;
/**
* 遷移対象の商品カテゴリ (Product Family)
* c/productFamilySelector によって設定されます
*/
@api targetCategory;
/**
* 不透明度に基づいて背景色のスタイル文字列を生成するGetter
* スライダーの値 (0-100) を alpha値 (0.0-1.0) に変換します
* @return {String} style string
*/
get overlayStyle() {
// 不透明度をCSS変数として渡す
const alpha = this.overlayOpacity / 100;
return `--overlay-alpha: ${alpha}`;
}
/**
* ボタンクリック時の遷移処理
* 設定されたカテゴリに基づいて検索ページやリストページへ遷移します
*/
handleNavigate() {
if (!this.targetCategory) {
// カテゴリが未設定の場合のハンドリング
console.warn('Category is not set.');
return;
}
// NavigationMixinを使用してページ遷移(実装例)
// ※実際の実装では、プロジェクトのサイト構造に合わせたPageReferenceを指定してください
this[NavigationMixin.Navigate]({
type: 'standard__search',
attributes: {
term: this.targetCategory
}
});
// 補足: B2B CommerceやLWRの製品リストページへ遷移する場合の例
// type: 'standard__webPage',
// attributes: { url: `/category/${this.targetCategory}` }
}
}
これで、アドミンはコードを触ることなく、「スライダーでの明度調整」と「組織データに基づくカテゴリ選択」が可能になりました。

さらに広がるCPEの可能性
今回は基本的なスライダーとリスト選択を紹介しましたが、CPEは「エディタ自体がLWC」であるため、JavaScriptで実装できることはほぼ何でも実現可能です。
例えば、以下のような高度な設定画面も作ることができます。
- JSONジェネレーター(リスト作成):
- 標準設定では難しい「Q&Aリスト」や「お客様の声」など、複数の項目(質問・回答・名前など)を持つリストデータを、画面上で追加・削除・並び替えしてJSON形式で保存します。
- ビジュアルアイコンピッカー:
- SLDSアイコン名をテキスト入力するのではなく、実際のアイコン一覧を表示して、クリックで直感的に選択できるUIを提供します。
- 外部API連携:
- Google Maps APIなどをエディタ内に表示し、地図をクリックして緯度経度を取得するなど、外部サービスと連携した設定補助が可能です。
- 条件付き表示制御:
- 「レイアウトA」を選んだ時だけ「画像URL」の入力欄を表示するなど、設定項目の依存関係をロジックで制御し、不要な項目を隠してスッキリさせることができます。
CPEを活用して、サイト運用者が「使いやすい!」「楽しい!」と感じる、プロフェッショナルな管理画面(UI)を提供しましょう。
参考URL
Lightning Web Components Dev Guide: Create a Custom Property Editor (※Experience Cloudでの利用も同様の概念に基づきます)




読者の声