見出し画像

Zag調べてみる

これは2023/7/3の社内勉強会の資料です。

Zagとは

フレームワークに依存せずに、複雑でインタラクティブでアクセシブルなUI Componentを構築できるライブラリで、Chakra UIから出ています。
現時点(2023年7月)ではbeta版です。

Zagの推しポイント

Powered by state machines 🌳: Zag is built on top of the latest ideas in Statecharts. We don't follow the SCXML specifications, but we've created an API that we think will help us build more complex components fast.
(日本語訳)
ステートマシンによる駆動 🌳: Zagは、Statechartsの最新のアイデアを基に構築されています。私たちはSCXMLの仕様に従っていませんが、より複雑なコンポーネントを迅速に構築するのに役立つAPIを作成しました。

Write once, use everywhere 🦄: The component interactions are modelled in a framework agnostic way. We provide adapters for JS frameworks so you can use it in React, Solid, or Vue 3.
(日本語訳)
一度書いて、どこでも使用 🦄: コンポーネントの相互作用はフレームワークに依存しない方法でモデル化されています。JSフレームワーク用のアダプタを提供しているため、React、Solid、Vue 3などで使用できます。

Focus on accessibility ♿️: Zag is built with accessibility in mind. We handle many details related to keyboard interactions, focus management, aria roles and attributes.
(日本語訳)
アクセシビリティに注目 ♿️: Zagはアクセシビリティを考慮して構築されています。キーボードの操作、フォーカス管理、ariaの役割と属性に関連する多くの詳細を管理します。

Headless ✨: The machine APIs are completely unstyled and gives you the control to use any styling solution you prefer.
(日本語訳)
ヘッドレス ✨: マシンのAPIは完全にスタイルがなく、あなたが好きなスタイリングソリューションを使用するためのコントロールを提供します。

Incremental adoption ✨: Adopt the machines as you need them. Each component machine is an NPM package and can be installed individually so you can use them incrementally.
(日本語訳)
段階的な採用 ✨: 必要に応じてマシンを採用してください。各コンポーネントマシンはNPMパッケージであり、個別にインストールできるため、段階的に使用することができます。

https://zagjs.com/overview/introduction#why-zag

アダプターを使って、React, Vue, SolidなどのJSフレームワークを跨いで使える点や、必要なComponentのみをnpm パッケージからimportできる点などから、今使ってる環境で小さく始めてみるアプローチとかが取りやすな印象を受けました。

また、a11yが考慮されてたり、headlessな見た目だったり、社内でデザインシステムこれから作ってくぜみたいな企業は採用してくのありな気がします。

やってみる

インストール

使いたいComponentと、JSフレームワーク毎に提供されてるアダプターをインストールします。一番シンプルそうなToggleでやってみます。

// toggle componentのインストール
yarn add @zag-js/toggle

// adapterのインストール
yarn add @zag-js/react

example

Toggle

import { useMachine, normalizeProps } from "@zag-js/react"
import * as toggle from "@zag-js/toggle"

export function Toggle() {
  const [state, send] = useMachine(toggle.machine({
    id: "1"
  }))
  const api = toggle.connect(state, send, normalizeProps)
  return (
    <button {...api.buttonProps}>
      {api.isPressed ? "On" : "Off"}
    </button>
  )
}

Dialog

import * as dialog from "@zag-js/dialog"
import { useMachine, normalizeProps, Portal } from "@zag-js/react"

export function Dialog() {
  const [state, send] = useMachine(dialog.machine({ id: "1" }))

  const api = dialog.connect(state, send, normalizeProps)

  return (
    <>
      <button {...api.triggerProps}>Open Dialog</button>
      {api.isOpen && (
        <Portal>
          <div {...api.backdropProps} />
          <div {...api.containerProps}>
            <div {...api.contentProps}>
              <h2 {...api.titleProps}>Edit profile</h2>
              <p {...api.descriptionProps}>
                Make changes to your profile here. Click save when you are done.
              </p>
              <div>
                <input placeholder="Enter name..." />
                <button>Save</button>
              </div>
              <button {...api.closeTriggerProps}>Close</button>
            </div>
          </div>
        </Portal>
      )}
    </>
  )
}

利用者側のやることはHTMLを書いて、それぞれの要素に適切なpropsを渡して、スタイルを書くだけになります。
ベータ版ですが、Componentのドキュメントが結構充実していて、
Anatomyのセクションを見ると、DOM構造の図があるので、イメージしやすいかと思います。また、Styling guideのセクションで、ある要素やある状態の時のdata属性も書かれているので、CSSを書く時の参考にできそうです。


実際に試したい方はこちら

ちなみに、今回は既に提供されているComponentを使いましたが、state machineを自作してオリジナルのComponentを作成することも可能そうです!!


まとめ

同様のライブラリでRadix などがあると思いますが、Radixは専用のComponentで見た目を組み立ててくのに対して、Zagの方はComponentの振る舞いをpropsで渡して組み立ていく方式なので、見た目と振る舞いをradix以上に分離できそうな印象を持ちました。また、フレームワークを跨いで使える点もZagの強みだと思うので、複数のJSフレームワーク使ってる場合とかは選択肢の一つとして考えてみるのもありかもしれません。

そういえば、推しのアイドルグループのEPの発売したので、とりあえず聞いてみてほしい