【Alpine.js】Laravelで簡単にタブ切り替え機能を実装

## すぐ使えるAlpine.js
Laravel開発で認証機能を実装する際、「Laravel Breeze」をインストールすることは多いと思います。

そこで**Alpine.js**を選択しておけば、JSファイルを用意したり、headタグにscriptタグを書いて読み込ませたりといった手間がないので、即コードを書くことができます。

ということでBreezeをインストールする前提で、Alpine.jsを利用して以下のようなシンプルなタブ切り替えのコンポーネントを作成します。

![画面収録 2024-12-01 21.55.26.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3783222/de2d4844-1c7d-81f1-9d33-9870caf02837.gif)


## 環境
- Laravel 10
- Laravel sail 8.3
- Laravel Breeze 1.29.1

## 準備

composerを使用してBreezeをインストールする際に「Blade with Alpine」を選択します。

![gMKqtLt.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3783222/a4cb6ed3-c73d-0af3-563b-860c07a0d579.png)

resourcesのapp.jsに以下の記述が確認できます。

```js:resources/js/app.js
import './bootstrap';

import Alpine from 'alpinejs';

window.Alpine = Alpine;

Alpine.start();
```

これでAlpineを使える状態になっていますので、さっそく書いていきましょう！

## コード

cssファイルを作成する手間も省くため、tailwindで書いていきます。
このファイル内にHTML、tailwind、php、jsと盛りだくさんです。

```php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Laravel</title>
  <link rel="preconnect" href="https://fonts.bunny.net">
  <link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet" />
  @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>

<body class="w-80 m-8">
  <div x-data="{ activeTab: 'buttonA' }">
    <!-- tabリストエリア -->
    <div class="flex" role="tablist">
      <button
        x-on:click="activeTab = 'buttonA'"
        :class="activeTab === 'buttonA' ? 'bg-indigo-300 text-white' : 'bg-white text-indigo-300'"
        class="w-full py-2 font-bold text-center border border-indigo-300"
        role="tab"
        aria-controls="buttonA"
        :aria-selected="activeTab === 'buttonA'">
        A
      </button>
      <button
        x-on:click="activeTab = 'buttonB'"
        :class="activeTab === 'buttonB' ? 'bg-indigo-300 text-white' : 'bg-white text-indigo-300'"
        class="w-full py-2 font-bold text-center border border-indigo-300"
        role="tab"
        aria-controls="buttonB"
        :aria-selected="activeTab === 'buttonB'">
        B
      </button>
    </div>

    <!-- tabパネルエリア -->
    <div role="tabpanel" class="mt-4" id="buttonA" x-show="activeTab === 'buttonA'">
      <div class="flex justify-center items-center p-8 border border-indigo-300 text-indigo-300 font-bold">
        <p>エリアA</p>
      </div>
    </div>
    <div role="tabpanel" class="mt-4" id="buttonB" x-show="activeTab === 'buttonB'">
      <div class="flex justify-center items-center p-8 border border-indigo-300 text-indigo-300 font-bold">
        <p>エリアB</p>
      </div>
    </div>
  </div>
  
</body>
</html>
```


ポイントは「x-」の接頭辞がついたプロパティです。

### x-data
x-dataで関数やプロパティ名を定義しておき、全体を囲んでいます。
ここでは「activeTab」になります。
最初にbuttonAとしているのはデフォルト値ですね。

### x-on:click
buttonに`x-on:click="activeTab = 'buttonA'"`を付与しており、クリックすることで、x-dataのactiveTabの値が切り替わります。

スタイルについては「:class」に三項演算子でスタイルを定義しています。
タブ切り替えによって変わる部分（背景色と文字色）をON、OFFどちらも設定しておきます。

### x-show
タブと連動して表示が切り替わる領域には、x-showに条件判定を入れています。
`x-show="activeTab === 'buttonA'"`とすることでtrueのときにdisplay: block、falseのときはdisplay: noneになります。

※実際にはaria-selectedなどの値も切り替わっていますが、サクッと説明のため割愛します！


## 実際につかってみて
フツーにPHPファイルにJSの処理を書けるのが非常に快適ですね。
Livewireを触ったときにも思いましたが、HTML 、CSS、JSなどを独学で学んでいたときには考えもしないような技術がたくさんあり、開発していてとても楽しいです！

まだ使い始めたばかりですので、もっと深掘って使っていきたいと思います。

## 参考
- [Alpine.js](https://alpinejs.dev/)
- [ARIA: tab ロール](https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Roles/tab_role)