【フロントエンド開発の基礎力】モーダル・ドロップダウン・タブをゼロから実装して理解を深める
1. はじめに 〜「なんとなく使う」から「理解して使う」へ〜
現代のWebアプリケーションにおいて、「モーダル」「ドロップダウン」「タブ」は当たり前のように登場するUIコンポーネントです。しかし、
- ライブラリを使えば一瞬で実装できるけど、実は仕組みが分かっていない
- スタイリングやイベントの扱いでバグが出やすい
という経験はないでしょうか?
本記事では、これらのUIをゼロから実装し、
「仕組みを理解した上で応用できる力」=基礎力を養うことを目的としています。
ReactやVueなどのフレームワークを使わず、プレーンなHTML/CSS/JavaScriptだけで実装し、挙動と構造の本質を掴みましょう。
2. 各UIコンポーネントの概要と実装の難所
2.1 モーダル(Modal)
定義:
画面上にオーバーレイとして表示されるダイアログ。背景の操作を無効化し、ユーザーに特定のアクションを促す。
実装時の課題:
- 背景スクロールの無効化
- ESCキーで閉じる処理
- アニメーションの扱い
2.2 ドロップダウン(Dropdown)
定義:
クリック時に表示される選択肢リスト。ナビゲーションやフォームで多用される。
実装時の課題:
- 外側クリックで閉じる挙動
- フォーカス管理
- レイアウトとの整合性(z-indexやoverflow)
2.3 タブ(Tab)
定義:
複数のセクションを切り替えるためのUI。SPAや管理画面でよく使われる。
実装時の課題:
- アクティブ状態の管理
- ARIA属性などアクセシビリティ考慮
3. 実装例:プレーンJSで作るミニUIコンポーネント
💡 前提:HTML構造とCSSはシンプルに保つ
以下のコードは基本形。まずはモーダルを例に説明し、次に他のUIも順に解説します。
3.1 モーダルの実装
HTML
<button id="openModal">Open Modal</button>
<div id="modal" class="modal hidden">
<div class="modal-content">
<span id="closeModal" class="close">×</span>
<p>Hello, this is a modal!</p>
</div>
</div>
CSS
.modal {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
justify-content: center;
align-items: center;
}
.modal.hidden {
display: none;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
}
JavaScript
const modal = document.getElementById('modal');
const openBtn = document.getElementById('openModal');
const closeBtn = document.getElementById('closeModal');
openBtn.addEventListener('click', () => {
modal.classList.remove('hidden');
document.body.style.overflow = 'hidden'; // 背景スクロール無効
});
closeBtn.addEventListener('click', closeModal);
window.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeModal();
});
function closeModal() {
modal.classList.add('hidden');
document.body.style.overflow = '';
}
3.2 ドロップダウンの実装
HTML
<div class="dropdown">
<button id="dropdownToggle">Menu</button>
<ul id="dropdownMenu" class="menu hidden">
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
JavaScript
const toggle = document.getElementById('dropdownToggle');
const menu = document.getElementById('dropdownMenu');
toggle.addEventListener('click', () => {
menu.classList.toggle('hidden');
});
document.addEventListener('click', (e) => {
if (!toggle.contains(e.target) && !menu.contains(e.target)) {
menu.classList.add('hidden');
}
});
3.3 タブの実装
HTML
<div class="tabs">
<button data-tab="1" class="tab active">Tab 1</button>
<button data-tab="2" class="tab">Tab 2</button>
</div>
<div id="content-1" class="tab-content">Content 1</div>
<div id="content-2" class="tab-content hidden">Content 2</div>
JavaScript
const tabs = document.querySelectorAll('.tab');
const contents = document.querySelectorAll('.tab-content');
tabs.forEach(tab => {
tab.addEventListener('click', () => {
tabs.forEach(t => t.classList.remove('active'));
contents.forEach(c => c.classList.add('hidden'));
tab.classList.add('active');
document.getElementById(`content-${tab.dataset.tab}`).classList.remove('hidden');
});
});
4. 実務で役立つTipsと落とし穴
- z-index地獄:UIが重なるとき、z-indexの値が中途半端だと表示されない。
- CSSのresetやnormalizeを導入することで、ブラウザ間の差異を防ぐ。
- レスポンシブ対応:モバイルではモーダルは画面全体にするなど、UI調整が必須。
- アクセシビリティの考慮:ARIA属性やキーボード操作の対応も将来的に必要。
5. 応用編:コンポーネント化と状態管理の導入
- 上記コードをWeb Component化して再利用性を高める
- 状態を**State Management(例:ReduxやContext API)**で統一的に管理する
- React/Next.jsなどでリファクタリングし、実際のアプリで活用
6. まとめ:自分の手で作ることが最強の学び
項目 | メリット | 注意点 |
---|---|---|
モーダル | 明確な操作を促す | スクロール制御やフォーカス移動 |
ドロップダウン | UIの整理に役立つ | z-indexや外部クリック検知 |
タブ | 情報の整理に適している | 状態管理とアクセシビリティ |
本記事で紹介したのは、UIコンポーネントの「基礎中の基礎」です。しかし、この地味な基礎力が、将来的にライブラリやフレームワークを使いこなす際の大きな武器になります。
🚀 次回予告:「画面遷移とシングルページアプリ」
📎 参考リンク
- MDN Web Docs: https://developer.mozilla.org/ja/
- A11yガイドライン: https://www.w3.org/WAI/