こんにちは、フロントエンドエンジニアのあおきです。
フォームUIを作っていると、こういう要件が出てきます。
- チェックされたらラベルの見た目を変えたい
- inputの状態に応じてテキストを表示したい
- フォーカス時に補助UIを出したい
通常のCSSならこう書きます。
input:checked + label { }
input:focus + .hint { }
ですがTailwindではCSSを書かずに実現できます。それが peer です。
この記事では、フォームUIで頻出する状態管理をCSSなしで実現するpeerの使い方を実務ベースで解説します。
peerとは
通常、CSSでは「親要素の状態によって子要素を変える(group)」ことは容易ですが、「ある要素の状態によってその後の兄弟要素を変える」には、隣接兄弟セレクタ(+)などが必要です。
Tailwindの peer クラスを使うと、HTMLの構造だけで「前の要素がフォーカスされたら、後ろの要素を出す」といった制御が完結します。
基本的な使い方
- トリガーとなる要素に peer クラスを付与する。
- 変化させたい要素(後ろにある兄弟要素)に peer-{modifier}: クラスを付与する。
<input type="email" class="peer ..." />
<p class="invisible peer-invalid:visible text-red-500">
無効なメールアドレスです
</p>
実務パターン① チェックボックスUI
See the Pen 実務パターン① チェックボックスUI by あおき (@himlinfq-the-encoder) on CodePen.
実務パターン② フォーカス時の補助テキスト
See the Pen 実務パターン② フォーカス時の補助テキスト by あおき (@himlinfq-the-encoder) on CodePen.
実務パターン③ バリデーション表示
See the Pen 実務パターン③ バリデーション表示 by あおき (@himlinfq-the-encoder) on CodePen.
実務パターン④ ラジオボタンUI
See the Pen 実務パターン④ ラジオボタンUI by あおき (@himlinfq-the-encoder) on CodePen.
よく使うpeer一覧
| クラス | 意味 |
|---|---|
| peer-checked | チェック状態 |
| peer-focus | フォーカス |
| peer-hover | ホバー |
| peer-invalid | バリデーションNG |
| peer-disabled | 無効状態 |
groupとの違い
| group | peer | |
|---|---|---|
| 関係 | 親子 | 兄弟 |
| 使い所 | カードUIなど | フォームUI |
| 例 | hover連動 | checked連動 |
よくあるミス
① 順番ミス
<label class="peer-checked:text-blue-500"></label>
<input class="peer">
→ 動かない
peerは「後ろの要素」にしか効きません、peerを先に記述しましょう
② 子要素に効くと思ってしまう
<label>
<input type="checkbox" class="peer">
<span>
<svg class="opacity-0 peer-checked:opacity-100"></svg>
</span>
</label>
→ 動かない
svg は input の兄弟ではなく「子要素」だから、peer は子要素には届きません、同じ階層に置くことで解決
③ hidden で input を消してしまう
<input type="checkbox" class="peer hidden">
→ 動かない
hidden は display: none; になるため操作できない
checked や focus が変わらないので peer も反応しない、sr-onlyに置き換えましょう
まとめ
peerを使うと
- フォームUIの状態変化(checked / focus / invalid など)をCSSだけで制御できる
- 兄弟要素同士の連動がシンプルに書ける
- これまでJavaScriptで実装していたUIの多くを置き換えられる
特にフォーム周りは「状態に応じた見た目の変化」が多く、実装が複雑になりがちです。
peerを使うことで、そのロジックをシンプルに保ったままUIを構築できます。
Tailwindを使うなら、groupと並んで必ず押さえておきたい機能のひとつです。