【LWC開発】システム管理者に「設定」を委譲しよう!Experience Cloud用 js-meta.xml 完全ガイド

この記事はバージョン Winter ’26 において執筆しています。
現在の動作と異なる場合がありますので、ご認識おきください。

LWC (Lightning Web Components) を開発する際、私たちはつい HTML や JavaScript のロジックに集中しがちです。 しかし、Experience Cloud 用のコンポーネントにおいて、最も時間をかけるべきファイルは js-meta.xml かもしれません。

なぜなら、このファイルの記述次第で、そのコンポーネントが「ただ動くだけの部品」になるか、「システム管理者がビルダー上で自由にカスタマイズできる柔軟な部品」になるかが決まるからです。

「タイトルを変えるたびにコード修正依頼が来る」 そんな不毛な運用を避けるために、今回は js-meta.xml を使い倒して、設定値をプロパティパネルに外出しする技術を解説します。

基本:Experience Cloud で使えるようにする

まず、開発したLWCをエクスペリエンスビルダーのコンポーネント一覧(左側のメニュー)に表示させるための最低限の設定です。 targetslightning__CommunityPage を指定します。

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>65.0</apiVersion>
    <isExposed>true</isExposed>
    
    <masterLabel>カスタムお知らせバナー</masterLabel>
    <description>お知らせを表示するバナーです。テキストと背景色を変更可能です。</description>
    
    <targets>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
    </targets>
</LightningComponentBundle>

核心:プロパティ(変数)を公開する

ここからが本題です。 JavaScript内で @api title; のように宣言した変数を、ビルダーの画面右側(プロパティパネル)から入力可能にします。

これには targetConfigs を使用します。先ほどの js-meta.xml を以下のように編集します。

実装例:タイトルと表示件数、フラグを設定可能にする

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>65.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>カスタムお知らせバナー</masterLabel>
    <description>テキスト、表示件数、色を変更可能なお知らせバナーです。</description>
    
    <targets>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
    </targets>

    <targetConfigs>
        <targetConfig targets="lightningCommunity__Default">
            
            <property 
                name="bannerTitle" 
                type="String" 
                label="バナータイトル" 
                default="重要なお知らせ" />
                
            <property 
                name="maxItems" 
                type="Integer" 
                label="最大表示件数" 
                default="5" min="1" max="10" />
                
            <property 
                name="showIcon" 
                type="Boolean" 
                label="アイコンを表示する" 
                default="true" />
                
            <property 
                name="themeColor" 
                type="String" 
                label="テーマカラー" 
                datasource="Blue, Red, Green, Gray" 
                default="Blue" />
                
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

このように記述することで、管理者はコードを触ることなく「タイトル」や「色」を変更できるようになります。

DXforce Point for Developers

変数名の命名規則

js-meta.xmlname 属性はキャメルケース(bannerTitle)で記述します。ケバブケース(banner-title)などは使用できないため注意してください。

JavaScript 側での受け取り方

メタデータ側で定義したプロパティは、JavaScript ファイル (.js) 側では通常の @api デコレータが付いたプロパティとして受け取ります。

html / js / css のサンプルを記載しておきます。

customNotificationBanner.html

<template>
    <div class={bannerClass}>
        
        <template lwc:if={showIcon}>
            <lightning-icon 
                icon-name="utility:info" 
                alternative-text="Info" 
                size="small" 
                class="slds-m-right_small">
            </lightning-icon>
        </template>

        <h2 class="slds-text-heading_medium">{bannerTitle}</h2>

        <p class="slds-m-left_small">
            最大表示件数: {maxItems} 件
        </p>
    </div>
</template>

customNotificationBanner.js

import { LightningElement, api } from 'lwc';

export default class CustomNotificationBanner extends LightningElement {
    @api bannerTitle;
    @api maxItems;
    @api showIcon;
    @api themeColor;

    get bannerClass() {
        // ベースのSLDSクラス + テーマ用クラス + レイアウト用独自クラス
        return `slds-box slds-theme_alert-texture theme-${this.themeColor.toLowerCase()} banner-layout`;
    }
}

customNotificationBanner.css

/* テーマカラーごとのスタイル定義 */
.theme-blue {
    background-color: #cce5ff;
    color: #004085;
    border-color: #b8daff;
}

.theme-red {
    background-color: #f8d7da;
    color: #721c24;
    border-color: #f5c6cb;
}

.theme-green {
    background-color: #d4edda;
    color: #155724;
    border-color: #c3e6cb;
}

.theme-gray {
    background-color: #e2e3e5;
    color: #383d41;
    border-color: #d6d8db;
}

/* コンポーネント全体の調整 */
.banner-layout {
    display: flex;
    align-items: center;
}

設置例

【LWR】CMSコンテンツを選択させる裏技

LWRサイトで特に強力なのが、Salesforce CMS のコンテンツ(画像やニュース) をビルダー上で選択させる機能です。 これは ContentReference という特殊な型を使用します。

<property 
    name="contentId" 
    type="ContentReference" 
    label="表示するCMSコンテンツ" 
    description="Salesforce CMSから画像やニュースを選択してください。" 
/>

これを設定すると、プロパティパネルに「コンテンツを選択」ボタンが現れ、管理者はCMSワークスペースから直接コンテンツを紐付けることができます。 取得した contentId を使って、LWC側でコンテンツの詳細情報を取得・表示することが可能になります。

参考までに、 ContentReference を使用したサンプルコンポーネントのソースコードを記載します。(※やっていることは標準の画像コンポーネントと同じです)

cmsImageDisplay.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>62.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>CMS画像表示</masterLabel>
    <description>CMSから選択した画像を表示します。</description>

    <targets>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
    </targets>

    <targetConfigs>
        <targetConfig targets="lightningCommunity__Default">
            <property
                name="contentKey"
                type="ContentReference"
                label="画像を選択"
                description="表示したいCMS画像を選択してください。"
                filter="cms_image"
            />
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

cmsImageDisplay.html

<template>
    <div class="cms-image-container">
        
        <template lwc:if={hasImage}>
            <img src={imageUrl} alt={altText} class="responsive-image" />
        </template>

        <template lwc:else>
            <div class="placeholder slds-box slds-theme_shade slds-text-align_center">
                <p>ビルダーのプロパティから画像を選択してください</p>
            </div>
        </template>

    </div>
</template>

cmsImageDisplay.js

import { LightningElement, api, wire } from 'lwc';
// 拡張CMSのコンテンツを取得するためのモジュール
import { getContent } from 'experience/cmsDeliveryApi';
import siteId from '@salesforce/site/Id';
import basePath from '@salesforce/community/basePath';

export default class CmsImageDisplay extends LightningElement {
    /**
     * js-meta.xml から渡されるコンテンツキー(ID)
     * ビルダーで選択されたコンテンツのユニークなキーが入ります
     */
    @api contentKey;

    imageUrl;
    altText;
    errorMessage;

    /**
     * コンテンツキーを使って、CMSから詳細データを取得
     */
    @wire(getContent, { 
        channelOrSiteId: siteId,
        contentKeyOrId: '$contentKey'
    })
    wiredContent({ error, data }) {
        if (data) {
            try {
                // getContent は単一のコンテンツオブジェクトを返す
                const content = data;
                
                if (content && content.contentBody) {
                    const body = content.contentBody;
                    // sfdc_cms__image (画像) コンテンツタイプの場合
                    if (body['sfdc_cms:media']) {
                        let url = body['sfdc_cms:media'].url;
                        // URLが相対パスの場合、サイトのベースパスと /sfsites/c を付与
                        if (url && url.startsWith('/') && basePath) {
                            // basePathが '/' で終わっている場合と url が '/' で始まっている場合の重複を避ける
                            const cleanBasePath = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
                            url = `${cleanBasePath}/sfsites/c${url}`;
                        }
                        this.imageUrl = url;
                        this.altText = content.title; // 代替テキストとしてタイトルを使用
                        this.errorMessage = undefined;
                    }
                }
            } catch (e) {
                console.error('CMSデータの解析に失敗しました', e);
            }
        } else if (error) {
            this.errorMessage = '画像の読み込みに失敗しました。';
            console.error('CMS Error:', error);
        }
    }

    /**
     * 画像が正しく取得できたか判定するゲッター
     */
    get hasImage() {
        return this.imageUrl != null;
    }
}

cmsImageDisplay.css

.cms-image-container {
    width: 100%;
    display: flex;
    justify-content: center;
}

.responsive-image {
    max-width: 100%;
    height: auto;
    border-radius: 4px; /* 任意:角丸 */
    display: block;
}

.placeholder {
    width: 100%;
    padding: 2rem;
    color: #706e6b;
}

まとめ:変更に強いコンポーネントを作ろう

LWC開発者の腕の見せ所は、複雑なロジックを書くことだけではありません。 「明日、要件が変わってもコードを修正しなくて済む設計」 をすることこそが、プロフェッショナルな仕事です。

  • 固定の文字列は String プロパティにする。
  • 表示制御の条件は Boolean プロパティにする。
  • スタイルは Select(データソース)で選ばせる。

js-meta.xml を活用して、システム管理者(未来の自分)に優しいコンポーネント開発を心がけましょう。

参考URL

Experience Cloud 用コンポーネント設定 (js-meta.xml)

XML設定ファイルの要素(ContentReference 型の仕様含む)

CMS配信API (experience/cmsDeliveryApi > getContent)

読者の声

タイトルとURLをコピーしました