HTMXとラジオボタンで、メニュータブを作る

## 作りたいもの

メニューリンクが並んでおり、どれかをクリックすると、その詳細が下に表示されるようなものを作ります。
Bootstrapでいうところの [ナビゲーションタブ](https://getbootstrap.jp/docs/5.3/components/navs-tabs/) のようなイメージです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3310353/ffaab99b-d5cc-70f2-f56c-ebb13bd9aedb.png)

## 環境

- HTMX ver2.0.3

## ディレクトリ構造

通常は、各種サーバサイドのフレームワークとテンプレートエンジンを使われると思いますが、今回は簡易的な説明のため、静的なhtmlファイル(active.html, link1.html, link2.html)を、index.htmlから呼び出します。

```
.
└── htmx-test/
    ├── index.html
    ├── active.html
    ├── link1.html
    └── link2.html
```

## HTML部分

[HTMXのドキュメント](https://htmx.org/docs/) を参考に、以下のように書きました。

hx-* は、わたしの使っているエディタでエラーが出たので、data-hx-* になっていますが、やっていることは同じです。

※ なお、HTMXは、headタグで読み込んであります。

```html:htmx-test/index.html
    <section id="nav-tab">
        <nav class="tab-menu">
            <input type="radio" name="menu-item" id="active" value="active" checked
                data-hx-get="./active.html" data-hx-trigger="change" 
                data-hx-swap="innerHTML" data-hx-target="#nav-tab>.tab-content"
            />
            <label for="active">Active</label>
            <input type="radio" name="menu-item" id="link1" value="link1" 
                data-hx-get="./link1.html" data-hx-trigger="change" 
                data-hx-swap="innerHTML" data-hx-target="#nav-tab>.tab-content"
            />
            <label for="link1">Link1</label>
            <input type="radio" name="menu-item" id="link2" value="link2" 
                data-hx-get="./link2.html" data-hx-trigger="change" 
                data-hx-swap="innerHTML" data-hx-target="#nav-tab>.tab-content"      
            />
            <label for="link2">Link2</label>
            <input type="radio" name="menu-item" 
                id="disabled" disabled value="disabled" />
            <label for="disabled">Disabled</label>
        </nav>
        <div class="tab-content">
            <div>This is Active page.</div>
        </div>
    </section>
```

読み込まれる側のHTMLも作っておきます。

```html:htmx-test/active.html
<div>This is Active page.</div>
```

```html:htmx-test/link1.html
<div>This is Link 1 page.</div>
```

```html:htmx-test/link2.html
<div>This is Link 2 page.</div>
```

ちなみに、たとえば、PHPのSymfony系統には、[isXmlHttpRequest()というメソッドがあるようです。](https://qiita.com/umekikazuya/items/d51b1bd3c6074cdfd234)

なのでもしかしたら、上記のactive.htmlのようなエンドポイントは不要で、index.htmlにアクセスするとき、

- 通常のアクセス => HTMLすべてを返却
- HTMX経由（内部的にはAJAX経由）のアクセス => divタグのフラグメントだけを返却

というような実装も可能なのかなと思っています。

Slim frameworkだと、次のような記事を見つけました。
[Slim 4 - HTMX Server-side Integration](https://odan.github.io/2023/08/12/slim-htmx.html)

## CSS部分

HTMXを使えば、HTMLにJavaScript操作用のclassセレクタを使用しなくて済むので、CSSも、見やすく書けます。

```css
#nav-tab{
    margin:0 auto;
    padding:.5rem;
    max-width:30rem;
    min-height:20rem;
    border:solid thin gray;
    border-radius: 8px;
    display:flex;
    flex-direction: column;

    > * {
        margin:0;padding:.5rem;
    }
    nav.tab-menu {
        display:flex;
        gap:.5rem;
        border-bottom: solid thin gray;

        input[type=radio] {
            display:none;
        }
        label {
            margin:0;padding:0 .5rem;
            line-height:1.5rem;
        }
        label:hover {
            color:white;
            background-color:navy;
            border-radius: 8px;
            cursor:pointer;
        }
        input[type=radio]:checked {
            + label {
               font-weight: bold;
            }
            + label:hover {
                color:inherit;
                background-color:inherit;
                cursor:inherit;
            }
        }
        input[type=radio]:disabled {
            + label {
                color:gray;
            }
            + label:hover {
                background-color:inherit;
                cursor:not-allowed;
            }
        }
    }
}
```

## 感想

これまでは、`.active` セレクターのようなものを、JavaScriptで付けたり消したりしていましたが、HTMXと、ラジオボタンを利用することで、手間が減りました。

HTMXは、クライアントサイドで状態を管理しようとすると、一気に難易度が上がってしまうので、極力、サーバーサイドで管理するか、今回のように、inputタグを使うなど、工夫が必要だと思っています。