GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Docs
  • Showcase
  • Community

This view

  • Original page
  • New address

GeezerVison is showing zagjs.com — Zag - Rapidly build UI components without sweating over the logic.

Sponsor on OpenCollective
View Zag.js on Github

Zag provides the component API for the Web

Get Started

Powered by Statecharts

Simple, resilient component logic. Write component logic once and use anywhere.

Accessible

Built-in adapters that connects machine output to DOM semantics in a WAI-ARIA compliant way.

Framework agnostic

Component logic is largely JavaScript code and can be consumed in any JS framework.

Machines handle the logic. You handle the UI

Zag machine APIs are completely headless and unstyled. Use your favorite styling solution and get it matching your design system.

  • Install the machine you need
  • Consume the machine
  • Connect machine to your UI
import * as numberInput from "@zag-js/number-input" import { useMachine, normalizeProps } from "@zag-js/react" import { useId } from "react" export function NumberInput() { // 1. Consume the machine const service = useMachine(numberInput.machine, { id: useId() }) // 2. Convert machine to the provided API const api = numberInput.connect(service, normalizeProps) // 3. Render the component return ( <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Enter number:</label> <div> <button {...api.getDecrementTriggerProps()}>DEC</button> <input {...api.getInputProps()} /> <button {...api.getIncrementTriggerProps()}>INC</button> </div> </div> ) }

Work in your favorite JS framework

Finite state machines for building accessible design systems and UI components. Works with React, Vue and Solid.

import * as numberInput from "@zag-js/number-input" import { useMachine, normalizeProps } from "@zag-js/react" import { useId } from "react" export function NumberInput() { const service = useMachine(numberInput.machine, { id: useId() }) const api = numberInput.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Enter number:</label> <div> <button {...api.getDecrementTriggerProps()}>DEC</button> <input {...api.getInputProps()} /> <button {...api.getIncrementTriggerProps()}>INC</button> </div> </div> ) }
<script setup> import * as numberInput from "@zag-js/number-input" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed, useId } from "vue" const service = useMachine(numberInput.machine, { id: useId() }) const api = computed(() => numberInput.connect(service, normalizeProps)) </script> <template> <div ref="ref" v-bind="api.getRootProps()"> <label v-bind="api.getLabelProps()">Enter number</label> <div> <button v-bind="api.getDecrementTriggerProps()">DEC</button> <input v-bind="api.getInputProps()" /> <button v-bind="api.getIncrementTriggerProps()">INC</button> </div> </div> </template>
import * as numberInput from "@zag-js/number-input" import { normalizeProps, useMachine } from "@zag-js/solid" import { createMemo, createUniqueId } from "solid-js" export function NumberInput() { const service = useMachine(numberInput.machine, { id: createUniqueId() }) const api = createMemo(() => numberInput.connect(service, normalizeProps)) return ( <div {...api().getRootProps()}> <label {...api().getLabelProps()}>Enter number:</label> <div> <button {...api().getDecrementTriggerProps()}>DEC</button> <input {...api().getInputProps()} /> <button {...api().getIncrementTriggerProps()}>INC</button> </div> </div> ) }
<script lang="ts"> import * as numberInput from "@zag-js/number-input" import { normalizeProps, useMachine } from "@zag-js/svelte" const id = $props.id() const service = useMachine(numberInput.machine, { id }) const api = $derived(numberInput.connect(service, normalizeProps)) </script> <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Enter number:</label> <div> <button {...api.getDecrementTriggerProps()}>DEC</button> <input {...api.getInputProps()} /> <button {...api.getIncrementTriggerProps()}>INC</button> </div> </div>
Enter number:
Properties
min
max
disabled

The better way to model component logic

Today, design systems are becoming a very popular toolkit for companies to create a cohesive and accessible user experience for their customers.

With the rise of component-driven development, there's an endless re-implementation of common widgets (tabs, menu, etc.) in multiple frameworks. These implementations tend to grow in complexity over time and often become hard to understand, debug, improve, or test.
We need a better way to model component logic.
Zag is a new approach to the component design process, designed to help you avoid re-inventing the wheel and build better UI components regardless of framework. Heavily inspired by XState, but built to make it easier to maintain, test, and enhance.

With Zag, we're abstracting the complex logic for many components into a cohesive, framework-agnostic system — giving you complete control over styling and providing a thin adapter for your favorite framework.

Welcome to the future of building interactive components!
Segun Adebayo

Segun Adebayo

Creator of Zag.js

Build your design system with state machines today

Get Started
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.