"The logo for the React open source JavaScript library" © Facebook (Licensed under CC BY 1.0)
"Tailwind CSS Logo" © Tailwind CSS (Licensed under CC BY 4.0)
この記事はReact Advent Calendar 2023 23日目の記事です。
- はじめに
- Semantic UI ReactベースのUIコンポーネントライブラリについて
- Semantic UI React が だんだん DIGGLE にマッチしなくなってきた話
- Tailwind CSSベースのUIコンポーネントライブラリについて
- Tailwind CSS を使うにあたって工夫している部分
- まとめ
- We're hiring!
はじめに
弊社DIGGLEではフロントエンド開発に向けたUIコンポーネントライブラリ*1を用意しています。
開発者はUIコンポーネントライブラリ上に用意されているコンポーネントを用いてUIを構成することができるため、 作業の効率化や一定以上のデザインの一貫性を担保できます。 私自身用意されたコンポーネントベースにUIの構築を行うことでデザインに関しての悩み事が削減でき、より本質的な部分について取り組むことができていると感じています。
UIコンポーネントライブラリはDIGGLEの持っているデザインシステムの一部として、デザイナーとエンジニア両名にとって重要な役割を担ってくれています。
以前まで、DIGGLEではそのUIコンポーネントライブラリをSemantic UI Reactをベースに組んでいました。 react.semantic-ui.com
ですがシステムや組織が大きくなるにつれて、Semantic UI Reactでは対応が難しい部分が見えてきました。 現在その難しい部分の解消に向けてデザインコンポーネントをTailwind CSSを用いて刷新する取り組みを行なっています。
今回は、なぜDIGGLEではUIコンポーネントライブラリのベースをSemantic UI ReactからTailwind CSSに移したのか?という点についてお話しさせていただきます。
Semantic UI ReactベースのUIコンポーネントライブラリについて
Semantic UI React は Semantic UI というCSSフレームワークをベースに構築されたUIコンポーネントライブラリです。
DIGGLEにおいての利用方法は、基本Semantic UI ReactをベースにDIGGLEでの使い方にマッチするよう薄くラップしたり、UIで頻出するコンポーネントを用意しておくといったものでした。
DIGGLEでの使い方にマッチするよう薄くラップ
Semantic UI ReactはとてもよくできたUIコンポーネントライブラリではあるのですが、 汎用的なものである以上細かい部分などどうしてもDIGGLEとマッチしていない部分があります。
そのためDIGGLEでは薄くラップする形でカスタマイズをしています。 どのようなカスタマイズを入れていたかについて具体的な例を列挙したいと思います。
Dropdownのpropsのデフォルト値を調整
DIGGLEではDropdownをさまざまな場面で利用しています。
Semantic UI ReactではDropdownコンポーネントも用意してくれており、
Semantic UI Reactのデフォルトではtrue
になっているselectOnNavigation
というpropsのデフォルトを、DIGGLEでは false に変更して利用しています。
こちらのパラメータはDropdownを開いている際に矢印キーを押すと、矢印で移動した先を選択状態にするかどうかというパラメータです。
DIGGLEではDropdownで選択が行われるとすぐにAPIを叩き、選択内容を反映するUIを多く採用しています。その影響で、selectOnNavigation
がtrue
になっているとユーザーが選択のために矢印キーを連打すると連打した分だけ反映のAPIを叩いてしまいます。
そのため多くの場合はselectOnNavigation
というpropsをfalse
に変更して利用しています。
コンポーネントを利用する側で対応することもできますが、新規参画していただいた方や久しぶりにDropdownコンポーネントを触る際に間違ってselectOnNavigation
がtrue
のままにしてしまわないようUIコンポーネントライブラリ側でデフォルトの値を変更しています。
TextAreaの高さを自動で調整できるように変更
説明やコメントなど長い文章を書く際にTextAreaを活用しています。
Semantic UI Reactで用意されているTextAreaは高さを指定して利用するためユーザーの入力に応じてコンポーネントの高さを変えることができませんでした。
DIGGLEではユーザーの入力に応じて高さを変えたい場合はreact-textarea-autosize
ライブラリを利用するよう変更しています。
UIで頻出するコンポーネントを用意
テーブルのヘッダーを固定
DIGGLEでは巨大なテーブルを扱う機会が多く、UXの観点からテーブルのスクロール時に行/列を固定したいことがありました。
固定の方法も2行まとめて固定したい、ヘッダーとフッター両方を固定したいなど多岐に渡ったため、Semantic UI ReactのTableを拡張して複雑な固定をできるコンポーネントをSSTable(Sugoi Scroll Tableの略。記憶に残るコンポーネント名で弊社エンジニアのセンスが光ります)という名前で用意していました。
Semantic UI React が だんだん DIGGLE にマッチしなくなってきた話
色々なカスタマイズを加えながら大切に育てていたUIコンポーネントライブラリですが、だんだんとDIGGLEの方向性にマッチしなくなってきました。
だんだん表現したいこととSemantic UI Reactで整合性が取れなくなってきた
DIGGLEのUIはSemantic UI Reactのデザインをベースに構築していたのですが、 P/L ( 損益計算書*2 ) を表示するレポートのデザインなど一部Semantic UI Reactを一切使わないコンポーネントが現れました。
つまり、DIGGLEが表現したいUIの中にSemantic UI Reactの表現ではカバーできないコンポーネントが現れ始めたのです。
カスタマイズが複雑になるコンポーネントが増えてきた
DIGGLEで実装したいUIを実現するために複雑なカスタマイズが必要なコンポーネントが出てきました。
例えば、計算式に関わるコンポーネントです。
DIGGLEではさまざまな場面で計算式を利用することができ、
計算式を使うことで勘定科目A
と勘定科目B
の月次の値を表示した行の下に A+B
の計算結果の行を表示させるといったことができます。
こちらの機能はとても活用いただいているのですが、実装時にはユーザーにどういったUIで入力をしていただくのか?という点が問題になりました。 結論としては、Semantic UI ReactのDropdownをカスタマイズで表現したのですが、結果として複雑なカスタマイズが必要になりました。
複雑なカスタマイズは保守性を下げてしまいますし、そもそもSemantic UI Reactで表現することが適切なのか?という疑問を抱かせることになりました。
Tailwind CSSベースのUIコンポーネントライブラリについて
Tailwind CSSはSemantic UI と同様にCSSフレームワークと呼ばれるフレームワークです。
A utility-first CSS framework packed with classes like flex, pt-4, text-center and rotate-90 that can be composed to build any design, directly in your markup.
と記載されている通り「ユーティリティファースト」なCSSフレームワークであり、flex, pt-4, text-center
といったTailwind CSS側が用意したユーティリティクラスを利用することでスタイルを適用することができます。
Tailwind CSSを既存CSSと比較した際の有用性については色々な記事で言及されています*3。
DIGGLEでは Tailwind CSSを使うに当たって Tailwind UIの実装をベースにしています。
Tailwind UI はまとまったコンポーネントを提供しているわけではなく、Tailwind CSSとHeadless UIを組み合わせてどのようなUIコンポーネントが構築できるかを見せてくれるものになっており、各種コンポーネントのページでは基本的なhtmlタグとユーティリティクラスを組み合わせたコードを見ることができます。
例えば、バッジでは下記のコードを見ることができます。
<span class="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10">Badge</span>
そのため、UIコンポーネントライブラリ側では上記のコードをコピーしつつ、DIGGLEにマッチするよう調整するような形になります。 Semantic UI Reactよりも自前で実装する必要がある部分が増えるものの、同時にカスタマイズ性が上がっています。
自前実装のコストを払ってカスタマイズ性を上げることで、よりDIGGLEの求めるUIを実現できるようになります。 さらに、基本的なhtmlタグとユーティリティクラスを組み合わせたものをベースとしているため計算式を入力するためのDropdownを作る際にも、 ライブラリ側の実装に振り回されるといったことなく、シンプルな実装で実現できるようになると思っています。
Tailwind CSS を使うにあたって工夫している部分
Tailwind CSSが現在のDIGGLEの方向性に合っていそうではあったのですが、Tailwind CSSはそのまま使うには自由度が高すぎました。
そのため一旦下記の運用を行なっています。
ユーティリティクラスの分割
Tailwind CSS を使うと発生する問題の一つに、ユーティリティクラスの肥大化があると思います。
DIGGLEもすでにその問題に当たっており、先ほどのバッジではどのユーティリティクラスがどういった影響を与えているのかをぱっと見で判断することは困難です。 ReactコンポーネントのPropsで見た目を後から調整しようと思った際に、想定と異なるスタイルに影響が出てしまう恐れがあります。
そのため、各種コンポーネントのpropsに注目してユーティリティクラスの切り分けを行うようにしています。
const getSizeClasses = ( size?: 'x-small' | 'small' | 'large' | 'medium' | 'x-large' ) => { switch (size) { case 'x-small': { return 'px-2 py-1 text-xs'; } case 'small': { return 'px-2 py-1 text-sm'; } case 'large': { return 'px-3 py-2 text-sm'; } case 'x-large': { return 'px-3.5 py-2.5'; } // "medium" default: { return 'px-2.5 py-1.5 text-sm'; } } };
lintによるユーティリティクラスの順番整理
ユーティリティクラスを人間が綺麗に管理するには限界があります。
順番などを定めようものならコードレビューのたびに間違いがあるかもわからない間違い探しが始まってしまいます。
DIGGLEではprettierとeslintのルールを導入することである程度はlinterに任せるようにしています。
まとめ
今回はUIコンポーネントライブラリを置き換えるにあたって、Tailwind CSSを採用しました。 DIGGLEを運用していく中で求めるUIコンポーネントの姿がSemantic UI Reactを導入したタイミングよりもクッキリと見えるようになったことでTailwind CSSの採用に踏み切りました。 そのため、Semantic UI Reactを採用した以前の意思決定にも間違いはないと思っています。
これからTailwind CSSを本格的に運用していく中でさまざまな問題に直面すると思いますが、フェーズごとに適切な対応が何かを模索することでユーザーにより良い価値を提供できると信じて取り組んでいこうと思います。
この記事が、プロジェクトのUIコンポーネントライブラリの構築に悩んでいる方の一助となれば幸いです。
DIGGLEのエンジニアのitoがお送りしました。
We're hiring!
DIGGLE では共にプロダクトを開発してくれるエンジニアを大募集中です。
少しでも興味があれば、ぜひ下記採用サイトからエントリーください。
カジュアル面談も実施しているので、気軽なお気持ちでご応募いただければと思います!
*1:UIコンポーネントライブラリは、UIを実装する際に利用できるReactコンポーネント群のことを指しています。GitHubでいうPrimerのようなものを社内向けに構築/公開しています。
*2:DIGGLEは管理会計のSaaSのため、ここでの損益計算書は変動損益計算書などの管理会計向けのものになります。
“変動損益計算書”の確認が優良企業への第一歩 | 情報誌「戦略経営者」 | 経営者の皆様へ | TKCグループ
*3:https://udemy.benesse.co.jp/development/system/tailwind-css.html