Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@zag-js/svelte

chakra-ui14.4kMIT1.2.1TypeScript support: included

The svelte wrapper for zag

ui-machines, state-machines, zag, svelte, use-machine, hook

readme

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, 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

Usage

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

export function ToggleGroup() {
  const [state, send] = useMachine(toggle.machine({ id: useId() }))
  const api = toggle.connect(state, send, 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 or solid 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

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 © Segun Adebayo

changelog

CHANGELOG

All notable changes to this project will be documented in this file.

For v0.x changelog, see the v0 branch

[Unreleased]

See the Changesets for the latest changes.

1.2.1 - 2025-02-27

Fixed

  • Progress: Allow for more precise (decimal) values.

  • Scroll Snap: Fix issue where getScrollPadding could return NaN in test environments.

  • Date Picker: Fix issue where onValueChange doesn't get called when value is cleared.

  • Number Input: Fix issue where allowOverflow was not implemented.

1.2.0 - 2025-02-26

Fixed

  • Signature Pad

    • Fix issue where hidden input throws a controlled warning in React due to the absence of readOnly or onChange.
    • Fix issue where calling getDataUrl in the onDrawEnd callback after clearing the signature pad does not return an empty string.
  • React: Improve Hot Module Replacement such that effects are replayed correctly. This removes the need to refresh the page for changes to take effect.

  • Toggle Group: Fix issue where calling api.setValue with an array doesn't work as expected.

  • Pin Input: Fix flushSync was called from inside a lifecycle method warning.

  • Vue: Fix issue where choose is not a function error could be thrown for some machines.

  • File Upload: Fix issue where win.DataTransfer could throw in testing environments.

  • Time Picker: Fix [@zag-js/dismissable] node is null or undefined warning when lazy mounting the content.

Added

  • Pin Input: Add support for count prop to improve SSR aria-label attribute.

1.1.0 - 2025-02-26

Fixed

  • Pin Input: Fix issue where editing existing values don't work as expected.

  • Number Input: Fix issue where value prop wasn't consumed in the machine.

  • Carousel: Fix issue where page was not consumed in the machine.

  • Textarea: Fix issue where ResizeObserver loop could throw undelivered notifications warning.

Added

  • Toggle: Bring back toggle machine.

  • Hover Card: Expose interaction outside handlers to hover card.

1.0.2 - 2025-02-24

Fixed

  • Collection: Widen items type to allow Iterable instead of just Array since we internally convert iterables to an array.

  • Carousel: Enforce required slideCount to ensure machine works as expected.

  • Framework Bindings: Fix issue where undefined values were not filtered out before resolving props.

  • React: Fix issue where flushSync warnings could be shown when unmounting a component.

1.0.1 - 2025-02-23

Fixed

  • Select: Fix regression where multiple: true doesn't work.

  • Timer: Fix issue where timer doesn't restart when startMs changes.

  • Toggle Group: Fix issue where data-focus doesn't get removed after blurring the toggle group.

  • Toast: Fix keyboard navigation issue where toast group skips the close button within the toast item and moves to the next focusable element in the document.

Added

  • Added <component>.Machine type to help when typecasting generic components like combobox and select.

1.0.0 - 2025-02-22

Changed

  • Core: Rewrite machines for increased performance and initial mount time. The results show roughly 1.5x - 4x performance improvements across components.

  • [Breaking] Toast

    • Require the creation of a toast store using createStore
    • Solid.js: Require the usage of <Key> component to render toasts

Fixed

  • Menu: Fix issue where context menu doesn't update positioning on subsequent right clicks.

  • Avatar: Fix issue where api.setSrc doesn't work.

  • File Upload: Fix issue where drag-and-drop doesn't work when directory is true.

  • Carousel

    • Fix issue where initial page is not working.
    • Fix issue where pagination sync broken after using dots indicators.
  • Timer: Fix issue where timer stops when switching tabs.