Chakra UI を使ってみる (+create-react-app)

6 min read読了の目安(約5800字

Chakra UI を試していきます。

始め方

# プロジェクトを作成する
$ yarn create react-app --template typescript chakraui-tryout
$ code !$

# プロジェクト内
$ yarn add @chakra-ui/react @emotion/react @emotion/styled framer-motion
$ yarn start

Chakra UI とは何か?

  • React (DOM) 用の UI コンポーネントフレームワーク
    • Material-UI みたいなスタイルの強制が行われるフレームワークではない
    • ある程度自分でスタイルを定義したい人向け。汎用性が高い。
  • Tailwind CSS + emotion みたいな感じ
    • 要するに、短いコードでたくさんのスタイルを定義できます (Tailwind)
      • Tailwind CSS と違い、面倒なセットアップ無しでスタイリングできる
      • ブレイクポイントとレスポンシブなど、概念は Tailwind CSS と同じ
      • React べったりなプロジェクトだと Tailwind と同じものだとみなせるかも
      • ちなみに、別に Tailwind には依存はしていないです
    • 要するに、コンポーネントをかなりカスタマイズできます (emotion)
  • TypeScript でちゃんと型付けされているので、安心して使える
  • モーダルダイアログなど、UI コンポーネントが用意されている
    • ただ、UI コンポーネント無しでもかなり使えると思います
  • テーマがある
    • React のルートコンポーネントを <ChakraProvider provider={...}> で囲めば OK
      • 別のところで同様に <ChakraProvider provider={...}>で囲めばそこだけテーマ切り替え可
    • ダークモードにも対応済み
  • 特に Next.js や Gatsby やらと使っても互換性の問題はなさそう
  • アクセシビリティに配慮されている
    • コンポーネントに aria-* 属性の定義あり
    • キーボードナビゲーションへの配慮もあり

Tailwind CSS にそっくりというのは、下記のような Tailwind CSS のコードを

const Hoge: React.FC = ({ children }) => (
  <div className="m-1 sm:m-10">{children}</div>
);

// Tailwind CSSを知らない人のために注釈しておくと、
// `m-1 sm:m-10` は
// margin が 基本的には 1 = 0.25 rem で、
// 画面サイズが sm サイズ以上の時は 10 = 2.5 rem にする(レスポンシブ対応する)という意味

次のように書き換えられることをいっています。

import { chakra } from "@chakra-ui/react";

const Hoge: React.FC = ({ children }) => (
  <chakra.div m={{ base: 1, sm: 10 }}>{children}</chakra.div>
);

// もしくはこういうふうに書いても可
const Hoge = chakra("div", {
  baseStyle: { m: { base: 1, sm: 10 } },
});

ためしに zenn.dev を作ってみる

ためしにこの記事を書いている zenn.dev の編集画面に似たものを作ってみます。

コンポーネントなど一切分けていませんが、下記のコードで再現できました。

(アイコンを使うには追加で yarn add @chakra-ui/icons が必要。)

export function App() {
  return (
    <Flex bg="gray.100" w="100vw" h="100vh">
      <Flex
        as="header"
        position="fixed"
        top={0}
        width="full"
        shadow="sm"
        py={4}
        px={8}
      >
        <Box>
          <IconButton
            aria-label="back"
            color="black"
            rounded="full"
            icon={<ChevronLeftIcon />}
          />
        </Box>
        <Spacer />
        <Box>
          <Button disabled colorScheme="blue">
            保存済み
          </Button>
        </Box>
      </Flex>
      <Box mt={"6rem"} mx="auto">
        <Heading as="h1" size="lg" fontWeight="bold">
          chakra-ui を使ってみる (+create-react-app)
        </Heading>
        <Flex mt={8}>
          <Box w={"50rem"} bg="white" rounded="md" p={4} shadow="lg">
            <ParagraphSkeleton />
            <ParagraphSkeleton />
            <ParagraphSkeleton />
            <ParagraphSkeleton />
            <ParagraphSkeleton />
            <ParagraphSkeleton />
            <ParagraphSkeleton />
            <ParagraphSkeleton />
            <ParagraphSkeleton />
          </Box>
          <Box ml={6}>
            <Box bg="white" rounded="full" p={1} shadow="lg">
              <IconButton
                aria-label="edit"
                bg="gray.300"
                color="white"
                rounded="full"
                mr={1}
                icon={<EditIcon />}
              />
              <IconButton
                aria-label="view"
                bg="white"
                color="gray.400"
                rounded="full"
                icon={<ViewIcon />}
              />
            </Box>
            <Box mt={3}>
              <IconButton
                aria-label="view"
                shadow="lg"
                bg="white"
                color="gray.400"
                rounded="full"
                icon={<AttachmentIcon />}
              />
            </Box>
            <Box mt={3}>
              <IconButton
                aria-label="view"
                shadow="lg"
                bg="white"
                color="gray.400"
                rounded="full"
                icon={<AddIcon />}
              />
            </Box>
          </Box>
        </Flex>
      </Box>
    </Flex>
  );
}

const ParagraphSkeleton = () => <Skeleton mb={4} h={"1rem"}></Skeleton>;

下記のような表示になります。

用意されているコンポーネント

よく使うやつ

たとえば、自分で作ると面倒な下記の定番コンポーネントが予め用意されています。

  • ダイアログ(モーダル可)
  • ドロワー(右からスッと出るオーバーレイ)
  • メニュー
  • トースト
  • スケルトン

各コンポーネントとも、他 UI ライブラリに比べて結構バラバラになっていて、カスタマイズ可能になっています。

たとえば、ダイアログであれば下記のようにダイアログごとのコンポーネントバラバラに指定していくことになります。

<AlertDialog isOpen onClose={onClose} leastDestructiveRef={undefined}>
  <AlertDialogOverlay>
    <AlertDialogContent>
      <AlertDialogHeader>ダイアログ</AlertDialogHeader>
      <AlertDialogBody>ダイアログの本文で〜〜〜す!</AlertDialogBody>
      <AlertDialogFooter>
        <Button onClick={onClose}>閉じる</Button>
      </AlertDialogFooter>
    </AlertDialogContent>
  </AlertDialogOverlay>
</AlertDialog>

各部分はカスタマイズ可能です。

<AlertDialogHeader fontSize="4xl">デカダイアログ</AlertDialogHeader>

トランジション

フェードインなど、子要素の表示にアニメーションを着けることもできます。

<Fade in={trueIfShown}>フェードイン表示される内容</Fade>

まとめ

  • よさげ
    • 汎用的
    • カスタマイズ可能
    • Tailwind CSS 特有のセットアップとか不要でライブラリを持ってくればいきなり使える
    • Tailwind と違い、TypeScript で型保護されているのと、わざわざバリエーションによる CSS 肥大化などを考慮しないで済む
    • コンポーネントの数は他ライブラリと比べると少ない気はするが、作ると面倒なコンポーネントは網羅されてる
  • 向いてなさげ
    • CSS セレクタを巧みに使ったスタイルは難しそう
    • 事前に CSS ファイルとして分離したりは難しそう

今後採用していきたいです。