意外と単純ではない TextBox が atom である理由

## はじめに

Dwango でニコニコ生放送のフロント開発を担当している @misuken です。

前回の記事 [普遍的な atom と molecule の境界を意識したコンポーネント設計](https://qiita.com/misuken/items/2ac793928f02a2f1d857) では、 **内包する構成要素が無ければ意味を成さないコンポーネントかどうか** を焦点にすることで、 atom と molecule を普遍的に、どのプロジェクトでも共通した粒度として扱えるようになることを紹介しました。

今回はその記事の最後で挙げていた TextBox SelectBox ComboBox のもっと奥深い粒度の話を掘り下げていきたいと思います。

## TextBox の粒度も単純ではない

`<input type="text" />` を出力するような TextBox というコンポーネントを作った場合、ほぼ 100% の人が atom として認識するでしょう。

しかし、ただのテキストボックスと言えどもそれより小さい粒度の物が存在しないとは言えません。

例えば Google の検索フォームの入力欄を見てみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41058/5cf1aae6-4210-1e3e-5f35-bfe3a9267332.png)


右端のボタン二つは入力欄とは別に置かれているボタンであると言えるのですが、入力をクリアするボタンは、関心の対象や責務の境界から捉えても、テキストボックスに標準搭載された機能と言えないでしょうか？

## テキストボックスのクリアボタン

テキストボックスのクリアボタンは、なぜテキストボックス標準搭載の機能と言えるのか。それは、以下のような理由からです。

- クリアボタンの責務が完全にテキストボックス内で完結している
    - 完全に閉じた責務であり、コンポーネント外で制御する必要がない
    - コンポーネントを使用する側としてはクリアボタン制御が隠蔽されていてほしい
- テキストボックスの入力状況とボタンの表示が密接に関係している
    - 空のときは非表示で、入力されると表示される
- テキストボックスを設置する全ての場所で要求される可能性がある

クリアボタンがこれだけテキストボックスと密接な関係にあり、テキストボックスが無ければクリアボタンの存在意義がないとなれば、標準搭載されていないと毎回要求された場所に実装するのは明らかに面倒です。

これを裏付けるように Edge では `<input type="text" />` に標準でクリアボタンが付いていたりします。

## 全てのブラウザで標準搭載されていないクリアボタン

Edge では標準搭載されているテキストボックスのクリアボタンですが、残念ながら全てのブラウザで標準搭載されているわけではありません。

そうなると、検索フォームを作る際「入力欄にテキストを入力したら出現するクリアボタンを付けてください」という要求が来たとき、自力で実装する必要が出てきます。

すると、ただの atom だと思っていたコンポーネントでクリアボタンも出力する必要が出てきます。

```html
<input type="text" class="text-box" /><button class="clear-button" />
```

ここで **内包する構成要素が無ければ意味を成さないコンポーネントかどうか** という知見を持ち合わせていないと、「あれ、原子だったはずが、さらに分解できる要素が出てきて分子っぽくなったぞ、 atom と molecule どっちが正しいんだろう？」と迷うことになってしまいます。

知見を持ち合わせていれば、クリアボタンはオプションであって、それが無くても主体であるテキストボックスの意味を成していることから、明確に atom と断言できるわけです。

## 意外とリッチなテキストボックス

クリアボタンは標準搭載されていないブラウザが多いのですが、 [type](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input) 属性を変えると、ブラウザに実装されている様々な要素が現れます。(実装されているかはブラウザによります)

### 数値

```html
<input type="number" />
```

スピンボタンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41058/417ebc56-7bfb-3d37-f561-50829ff259ab.png)


### 日付

```html
<input type="date" />
```

日付ピッカーが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41058/2a534a7f-6997-5535-f5df-05fae6e8b36b.png)


## 属性は粒度に影響を与えない

属性を変えただけでコンポーネントの粒度が変わってしまっては、それこそ収拾がつかなくなってしまうので、テキストボックスはどんなリッチな補助機能が付いたとしても TextBox を主体としている以上 atom であり続けるべきです。(あくまで TextBox の表現の違いでしかないため)

TextBox という役割が atom であると捉えれば、これ以上分割できないことがわかります。

## 自作コンポーネントとの整合性

テキストボックスであれば、 `<input type="text" />` を使って実装するのが当たり前ではありますが、 `<input type="number" />` のスピンボタンのスタイルが気に入らないなど、ブラウザ標準では対応できないこともあるでしょう。

大抵は CSS で変更可能なように疑似要素が用意されているのですが、それでも対応できない場合もあります。

そのような場合は、同等の機能をコンポーネントとして自作するしかありません。

このような場合も、クリアボタンのときと同様に、 `<input type="number" />` に対してボタン要素などを追加する必要が出てきます。

もし、単純に要素の数だけでコンポーネントの粒度を切り替えていたとしたら、 `<input type="number" />` は atom だけど、自作スピンボタンを追加したほうのコンポーネントは molecule というように、全く同じ表示で全く同じ機能を有していながら粒度が違うことになってしまいます。

このように物理的な視点で粒度を捉えてしまうと、適切な粒度管理が行えなくなってしまうことがわかります。

## 粒度を物理で捉えない

粒度というと物理的な印象を受けますが、要素を物理的に捉えて粒度とすると破綻します。
これが粒度設計でハマりやすいポイントになっていのかもしれません。

[BCD Design](https://qiita.com/misuken/items/19f9f603ab165e228fe1) で言うところの Base つまり UI の型名で粒度を捉えられれば、普遍的な粒度を手に入れることが可能です。

そのため、コンポーネント名の末尾に安定して洗練された UI の型名を付けることが、コンポーネントの像をより明確にし、粒度が明確になることで依存関係も明確になるなど、様々な曖昧さを排除するメリットに繋がります。

このように、一切の主観を含まず正規化された結果は普遍であるため、プロジェクトを横断しても利用可能な長期的な資産となります。

## さらに奥深い粒度の話

まだ SelectBox と ComboBox の話を書いていませんが、長くなったので今回はここまでにしておきます。