次にくる?!Radix UI触ってみた(Radix UI × Tailwind CSS)
はじめに
この記事はQiitaに投稿した2022年アドベントカレンダーの記事を移管したものです。
Radix UI 概要
Why wastetime reinventing UI components?
Radixとは2022年7月22日にメジャーリリースされたUI Component Library
その特徴はHeadlessであること、そしてコンポーネントの種類の豊富さです。
ここで言うHeadlessとはスタイルがないことで、
UI Componentを「機能」と「見た目」に分けそのうち機能のみを提供するというもの
つまりHeadlessなUI Component LibraryはスタイルがないアクセシブルなUIコンポーネントを提供してくれます。
Headless な UI Component Library、Radixの他ではその名の通り”Headless UI”というTailwind CSSの開発元としてもお馴染みTailwind Labsの提供するUI Component Libraryもありますが、2022年12月時点でもコンポーネントの種類は少し寂しい…
一方、RadixはDialogやPopoverなどメジャーなコンポーネントはもちろん、TooltipやToastなど比較的豊富な種類のコンポーネントを提供しています。
本記事では導入方法からRadixでコンポーネントを実装するまで一通り触れてみたいと思います!
最終系
導入方法
Radixは使いたいコンポーネントごとにinstallします。
今回はswitchをinstall
% yarn add @radix-ui/react-switch
とりあえず最低限の実装してみる
今回はRadix UIとTailwind CSSでコンポーネントを実装したいとおもいます。
とりあえずJSXで実装
import React from "react";
import * as Switch from "@radix-ui/react-switch";
const MySwitch = () => {
return (
<form>
<div>
<label htmlFor="notification">通知を受け取る</label>
<Switch.Root id="notification">
<Switch.Thumb />
</Switch.Root>
</div>
</form>
);
};
MUI等のスタイルを包括したUI Componentと違い現時点ではスタイルがなくlabelしか見えない状態に...
Styling
さて、このままtailwindCSSでStylingしていくのですが1つ問題が...
状態によるStyling、例えばswitchがonの状態、offの状態でStylingを分ける必要があります。
Radixではコンポーネントの状態がdata-state
で管理されています。
When components are stateful, their state will be exposed in a
data-state
attribute. For example, when an Accordion Item is opened, it includes adata-state="open"
attribute.
switch onの時 | switch offの時 |
---|---|
ですので単にCSSでStylingする場合は下記のような方法でswitchがonの状態、offの状態で背景色を変更することができます。
.hogehoge {
background-color: white;
}
.hogehoge[data-state='checked'] {
background-color: black;
}
しかしTailwindでは任意のHTML attributesでのStylingを直接サポートしていないため新たにtailwindcss-radixというライブラリを使用することにします。
Install
% yarn add tailwindcss-radix
tailwind configのpluginに設定
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: {
extend: {},
},
plugins: [require("tailwindcss-radix")()], // 追記
}
これによりtailwindで簡単にdata-stateのchecked uncheckedをベースにStylingできるようになりました。
下記のようにradix-state-
というPrefixによってRadixのdata-state
にアクセスできます。
(Prefixを任意のものに設定もできるが今回は割愛)
const MySwitch = () => {
return (
<form>
<div>
<label htmlFor="notification">通知を受け取る</label>
<Switch.Root className="radix-state-checked:bg-black radix-state-unchecked:bg-gray-600" id="notification"> // tailwind追加
<Switch.Thumb />
</Switch.Root>
</div>
</form>
);
};
最終的な実装
あとは最終系を目指してコツコツとTailwind CSSでStylingしていきます....
const MySwitch = () => {
return (
<form>
<div className={clsx("flex", "items-center")}>
<label
className={clsx("text-base", "pr-3", "select-none")}
htmlFor="notification"
>
通知を受け取る
</label>
<Switch.Root
className={clsx(
"group",
["w-[42px]", "h-[25px]"],
["inline-flex", "flex-shrink-0"],
["bg-gradient-to-r", "from-[#EC008C]", "to-[#FC6767]"],
"relative",
"cursor-pointer",
"rounded-full",
"shadow-md",
[
"radix-state-checked:bg-black",
"radix-state-unchecked:bg-gray-600",
"radix-state-checked:focus:ring",
"radix-state-unchecked:focus:ring-1",
],
["focus:outline-none", "focus:ring-white"],
["transition-colors", "duration-200", "ease-in-out"],
["border-2", "border-transparent"]
)}
id="notification"
>
<Switch.Thumb
className={clsx(
["inline-block", "h-[21px]", "w-[21px]"],
"transform",
"rounded-full",
"group-radix-state-checked:translate-x-5",
"bg-white",
"shadow-lg",
"ring-0",
"pointer-events-none",
["transition", "duration-200", "ease-in-out"],
"group-radix-state-unchecked:translate-x-0"
)}
/>
</Switch.Root>
</div>
</form>
);
};
export default MySwitch;
まとめ & 感想
MUI等のドキュメントのコピペだけである程度綺麗に実装できるUI Componentに慣れていたので、0からStylingするのは少し大変でしたが、
プロダクトをより洗練されたものにしたい!
UI/UXにとことん拘りたい!
という方には強くお勧めできると思います!
個人的にもHeadlessなUI ComponentはHeadless UIしか選択肢になく、その種類の乏しさから導入には消極的でしたが、Radix UIの豊富さを受け、今後個人開発等でも積極的に取り入れていきたいと思います。
Let's Radix !
Discussion