Web Componentsは、独自HTML要素と、その内部構造・見た目をブラウザ標準APIで部品化する技術群です。Custom Elements、Shadow DOM、<template>と<slot>を組み合わせ、フレームワークをまたいで使えるUI部品を作れます。
情報確認日:2026年8月20日
結論:小さく独立した部品から採用する
向いているもの
- プロフィールカード、埋め込みプレイヤー、評価表示など境界が明確な部品
- WordPress、静的HTML、Reactなど複数環境で共有したい部品
- 内部CSSの衝突を避けたい部品
サイト全体のルーティングや複雑な状態管理までWeb Componentsだけへ任せる必要はありません。既存フレームワークと併用できます。
実際にCustom Elementを生成する
WORKING DEMO
<devs-profile-card>を定義してShadow DOMへ描画
下のカードはページ読み込み時に独自要素へ置き換えられます。「詳細を表示」の処理もShadow DOM内にあります。
Web Componentsを構成する3技術
| 技術 | 役割 | 必須か |
|---|---|---|
| Custom Elements | 独自タグとライフサイクルを登録 | 中心機能 |
| Shadow DOM | 内部DOMとCSSの境界を作る | 必要に応じて |
| template / slot | 再利用する構造と外部から差し込む場所を定義 | 必要に応じて |
3つを必ず全部使う決まりはありません。まずCustom Elementで意味のある境界を作り、CSS隔離が必要ならShadow DOM、利用者が内容を差し替えるならslotを追加します。
最小のautonomous custom element
独自要素名にはハイフンが必要です。profile-cardのように命名し、同じ名前を二度登録しないよう確認します。
class ProfileCard extends HTMLElement {
connectedCallback() {
if (this.dataset.ready === 'true') return;
this.dataset.ready = 'true';
const name = this.getAttribute('name') ?? 'Unknown';
this.textContent = `プロフィール: ${name}`;
}
}
if (!customElements.get('profile-card')) {
customElements.define('profile-card', ProfileCard);
}
<profile-card name="さかそ"></profile-card>
connectedCallback()は要素がdocumentへ接続されるたび呼ばれる可能性があります。イベントリスナーやDOMを重複追加しない設計にします。
Shadow DOMで内部を分離する
class ProfileCard extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const wrapper = document.createElement('article');
const heading = document.createElement('h2');
heading.textContent = this.getAttribute('name') ?? 'Unknown';
wrapper.append(heading);
shadow.append(wrapper);
}
}
Shadow DOM内の要素はページ側の一般的なCSSセレクターから影響を受けにくくなります。一方で、サイト共通の文字色やフォーカススタイルも自動では届かない場合があります。CSSカスタムプロパティ、::part()、属性など、利用側が調整できる公開面を設計します。
templateとslotで内容を差し込む
<template id="profile-template">
<article class="card">
<h2><slot name="name">名前未設定</slot></h2>
<div><slot></slot></div>
</article>
</template>
<profile-card>
<span slot="name">さかそ</span>
<p>フロントエンドの検証記事を作っています。</p>
</profile-card>
slotへ入る内容はlight DOM側に残るため、ページの文章として扱いやすい利点があります。部品の利用者が何を差し込めるか、名前付きslotと既定内容を文書化します。
ライフサイクルを使い分ける
constructor():初期構造やShadow Rootの準備。属性や親DOMに依存しすぎないconnectedCallback():document接続後の初期化、イベント登録disconnectedCallback():購読、Observer、タイマーの解除attributeChangedCallback():監視対象属性の変更反映
static get observedAttributes() {
return ['name'];
}
attributeChangedCallback(attribute, oldValue, newValue) {
if (attribute === 'name' && oldValue !== newValue) {
this.renderName(newValue);
}
}
ReactやVueとの違い
| 比較 | Web Components | フレームワーク |
|---|---|---|
| 実行基盤 | ブラウザ標準 | 各ランタイム・ビルド |
| 主な範囲 | 独立UI部品 | アプリ全体の状態・画面設計まで |
| 共有先 | 異なる環境へ配布しやすい | 同じフレームワーク内で統合しやすい |
| CSS境界 | Shadow DOMを選べる | 方式はフレームワークやCSS構成次第 |
二者択一ではありません。デザインシステムの最小部品をWeb Componentsで配り、アプリの状態管理はReactやVueが担う構成も可能です。イベントとプロパティの受け渡し方法を先に決めます。
アクセシビリティとフォームで注意すること
独自タグを作っても、buttonやinputの標準動作が自動で付くわけではありません。内部ではネイティブ要素を優先し、ラベル、フォーカス順、キーボード操作、エラー通知を確認します。フォーム連携が必要ならform-associated custom elementsを検討しますが、単純な用途なら標準inputをラップする方が安全です。
よくある失敗と解決策
Shadow DOMを使えばCSS問題がすべて消える
内部は守れますが、テーマ連携やアクセシビリティの調整口も減ります。色・余白はCSSカスタムプロパティ、限定箇所はpartとして公開します。
connectedCallbackのたびにイベントを追加する
要素の移動や再接続で多重登録になります。初期化済みフラグ、constructorでの一度だけの登録、disconnected時の解除を使い分けます。
customized built-in elementを前提にする
環境差を避けるなら、まずHTMLElementを継承するautonomous custom elementを中心にします。対象ブラウザと利用環境を検証してください。
導入チェックリスト
- 部品の責任が1文で説明できる
- 属性、プロパティ、イベント、slotの公開契約が決まっている
- 再接続時に処理やイベントが重複しない
- Shadow DOM外からテーマ調整できる
- JavaScript失敗時にも重要な内容へ到達できる
- キーボード、読み上げ、ズームで確認した
まとめ
Web Componentsは、ブラウザ標準で独自要素の境界を作り、必要に応じてShadow DOMとslotを組み合わせる仕組みです。まず小さく独立した部品をautonomous custom elementとして実装し、ライフサイクルの後始末とアクセシビリティ、外部から調整する公開面まで設計してください。