zag is a free, open source design & prototyping project written in TypeScript and released under MIT. It has 5,220 GitHub stars, 291 forks and 26 open issues, and was last pushed 23 hours ago. On this registry it ranks #39 of 62 tracked projects in Design & Prototyping, with 5 head-to-head comparisons available.

What is zag?

Zag is an MIT-licensed TypeScript library of framework-agnostic, headless component state machines for building an accessible design system once and consuming it in React, Solid, Vue, Svelte or vanilla JavaScript.

What it is

Zag models the interaction logic behind common UI components — Tabs, Menu, Modal, Toggle Group, Tooltip and others — as finite state machines, and ships them completely unstyled. Each component is published as its own npm package, such as @zag-js/dialog or @zag-js/tooltip, with thin adapters — @zag-js/react, @zag-js/vue, @zag-js/solid and @zag-js/svelte — so the same machine can be driven by React hooks, a Vue composition, Solid utilities or Svelte utilities. The machines are built on ideas from Statecharts, although the project deliberately does not follow the SCXML specification, and the guiding principles ask that they stay lightweight and avoid complex machine concepts such as spawn and nested states.

The problem it addresses is the endless re-implementation of the same component patterns in every framework a team supports. The README describes the rise of design systems and component-driven development producing duplicate Tabs, Menus and Modals whose differences mostly come down to each framework's reactivity and effects system, for example useState and useEffect in React. Those framework-specific implementations tend to grow in complexity and become hard to understand, debug, improve or test. Zag replaces them with one machine per pattern plus a small adapter.

Key capabilities

  • Framework-agnostic machines with adapters published as @zag-js/react, @zag-js/vue, @zag-js/solid and @zag-js/svelte, alongside vanilla usage.
  • Completely unstyled machine APIs, leaving the choice of styling solution entirely open.
  • Accessibility handled inside the machine: keyboard interactions, focus management, and ARIA roles and attributes.
  • Component logic and end-to-end tests modelled on the WAI-ARIA authoring practices, on the principle that component patterns should work the same way regardless of framework.
  • Per-component installation with npm i --save @zag-js/{component}, for example @zag-js/toggle-group.
  • A consistent consumption API across frameworks through useMachine, normalizeProps, machine() and connect().
  • Builds managed with esbuild and Turborepo; the build command emits CJS, ESM and DTS files, and examples/ ships start-react (Next.js TypeScript), start-vue (Vue 3 TypeScript), start-solid and start-svelte starters.

Who uses it and how

  • Teams maintaining a design system across more than one framework, who want component behaviour written and tested once rather than once per framework.
  • Accessibility-focused teams that need keyboard handling, focus management and ARIA attributes built into the primitive instead of added afterwards.
  • Product teams with an existing styling system that need behaviour only, since Zag supplies no visual design.
  • Teams working across Next.js, Vue 3, Solid or Svelte codebases, using the framework starters in the repository as a template.
  • The project records 5,219 stars, 291 forks and 26 open issues.

Getting started

Install the machine for the component required with npm i --save @zag-js/{component} (or yarn add @zag-js/{component}), then add the adapter package for the framework in use, such as @zag-js/react. Documentation is published at zagjs.com, and changelog entries are kept in CHANGELOG.md.

How it compares

No list of paid products or named alternative libraries is provided in the facts, so on the available evidence Zag stands alone in this registry. Its only stated point of contrast is the framework-specific re-implementation of common component patterns that its README describes as the problem it solves.

When to use it — and when not to

Zag suits teams that are willing to own the markup and the styling themselves and want the interactive, accessible behaviour delivered as a tested machine; it is MIT-licensed, so there is no vendor lock-in or cost model to weigh. It is a poor fit for anyone wanting a finished, styled component library out of the box, because every machine is headless and unstyled. Adopters should also be comfortable with state machine concepts and prepared to rely on the documentation site and the repository's examples, since the README is short and assumes familiarity with the approach.

project readme (upstream, from github) — read inline
Zag.js hero image

Zag

NPM Downloads Github Stars Discord

Finite state machines for accessible JavaScript components

  • Write once, use everywhere 🦄: The component interactions are modelled in a framework agnostic way. We provide adapters for JS frameworks like React, Solid, Svelte, or Vue.
  • Focus on accessibility ♿️: Zag is built with accessibility in mind. We handle many details related to keyboard interactions, focus management, aria roles and attributes.
  • Headless ✨: The machine APIs are completely unstyled and gives you the control to use any styling solution you prefer.
  • 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.

Documentation

To see the documentation, visit zagjs.com/

Releases

For changelog, Check CHANGELOG.md


Problem

With the rise of design systems and component-driven development, there's an endless re-implementation of common component patterns (Tabs, Menu, Modal, etc.) in multiple frameworks.

Most of these implementations seem to be fairly similar in spirit, the differences being around the reactivity and effects systems for the framework (e.g. useState, useEffect in React.js). Framework specific solutions tend to grow in complexity over time and often become hard to understand, debug, improve or test.

Solution

Zag is a JavaScript API that implements common component patterns using the state machine methodology.

Installation

npm i --save @zag-js/{component}

# or

yarn add @zag-js/{component}

{component} represents any component machine like dialog (@zag-js/dialog), tooltip (@zag-js/tooltip) , etc.

For framework specific solutions, we provide simple wrappers to help you consume the component state machines.

  • ⚛️ @zag-js/react - React hooks for consuming machines in React applications
  • 💚 @zag-js/vue - Vue composition for consuming machines in Vue applications
  • 🎷 @zag-js/solid - Solid.js utilities for consuming machines in Solid.js applications
  • 🎷 @zag-js/svelte - Svelte utilities for consuming machines in Svelte applications

Usage

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

export function ToggleGroup() {
  const service = useMachine(toggle.machine({ id: useId() }))
  const api = toggle.connect(service, normalizeProps)

  return (
    <div {...api.getRootProps()}>
      <button {...api.getItemProps({ value: "bold" })}>B</button>
      <button {...api.getItemProps({ value: "italic" })}>I</button>
      <button {...api.getItemProps({ value: "underline" })}>U</button>
    </div>
  )
}

Guiding Principles

  • All component machines and tests are modelled according to the WAI-ARIA authoring practices
  • Write end-to-end tests for every component based on the WAI-ARIA spec. Regardless of the framework, users expect component patterns to work the same way!
  • All machines should be light-weight, simple, and easy to understand. Avoid using complex machine concepts like spawn, nested states, etc.

Fun Facts

Zag means to take a sharp change in direction. This clearly describes our approach of using state machines to power the logic behind UI components.

Teasers

  • When you see someone using classic react, vue, solid or svelte to build an interactive UI component that exists in Zag, tell them to "zag it!" ⚡️

  • Anyone using Zag will be called a "zagger" 💥

  • The feeling you get when you use Zag will be called "zagadat!" 🚀

  • The Zag community will be called "zag nation" 🔥


Commands

Build commands

Our build is managed with esbuild and turborepo to provide fast, concurrent builds across the packages.

  • build : Build the CJS, ESM and DTS files. This is the actual production build that we run in the CI.

Examples

Since zag is framework agnostic, we need a way to test it within a framework. The examples/ directory includes starter projects for the frameworks we support.

  • start-react : Starts the Next.js TypeScript project
  • start-vue : Starts the Vue 3 TypeScript project
  • start-solid : Starts the Solid TypeScript project
  • start-svelte : Starts the Svelte TypeScript project

E2E Tests

We've setup end-to-end tests for every machine we built. We use Playwright for testing and we ensure that the component works the same way regardless of the framework.

  • e2e-react : Starts the E2E tests for the React project
  • e2e-vue : Starts the E2E tests for the Vue project
  • e2e-solid : Starts the E2E tests for the Solid project

Contributing new machines/features

  • generate-machine : Generates a new machine package in the packages/ directory. It sets up the required files and structure for new machine.
  • generate-util : Generates a new utility package in the packages/utilities directory.

Other commands

  • test : Run the tests for all packages
  • lint : Lint all packages

Website

  • start-website: Starts the website

Inspirations


Contributions

Looking to contribute? Look for the Good First Issue label.

🐛 Bugs

Please file an issue for bugs, missing documentation, or unexpected behavior.

💡 Feature Requests

Please file an issue to suggest new features. Vote on feature requests by adding a 👍. This helps maintainers prioritize what to work on.


License

MIT © Chakra Systems Inc.

Frequently asked questions

Is zag free to use?

zag is open source under the MIT licence. There is no licence fee and no seat count — you can self-host it or, where the project offers one, pay a vendor for a managed version instead.

What does zag do?

Build your design system in React, Solid, Vue, Svelte or Vanilla. Powered by finite state machines

What is zag written in?

zag is primarily written in TypeScript. Its source is publicly available at https://github.com/chakra-ui/zag, and it has 5,220 GitHub stars.