Installation

bun add marko-zag

Then add the Zag machine packages you actually use, e.g.:

bun add @zag-js/dialog @zag-js/switch @zag-js/tooltip

Requirements

Requirement Version
Marko ^6.3.34 (peer dependency)
Zag.js machines 1.x (the adapter tracks @zag-js/core@1.43.0)
Bundler Marko-aware (see below)

A Marko-aware bundler is required

marko-zag ships source, not compiled output: the package exports
./src/index.ts directly, and the four tags are .marko files. Marko tags
cannot be usefully pre-compiled by a library — compilation happens in the
context of the consuming app (server vs. browser output, Marko version,
optimization flags). So your build must run node_modules sources through
the Marko compiler and a TypeScript-capable loader.

Any standard Marko 6 setup qualifies:

  • marko-run — works out of the box.
  • Vite with @marko/vite — works out of the box (Vite transpiles TS in
    dependencies it processes).

If you maintain a custom webpack/rollup config, make sure .marko and .ts
files inside node_modules/marko-zag are not excluded from your loaders.

Taglib auto-discovery

marko-zag ships a marko.json taglib definition:

{
  "tags-dir": "./src/tags"
}

The Marko compiler discovers taglibs of installed dependencies
automatically, so <machine-props>, <service>, <connect>, and
<portal> are available in every .marko file of your app with no
imports and no configuration
. Editor tooling (the Marko VSCode extension /
@marko/type-check) picks up the same definitions, including each tag’s
TypeScript Input interface.

TypeScript

The TypeScript exports are consumed straight from source, so your
tsconfig.json needs moduleResolution set to "bundler" (marko-zag’s
internal imports use explicit .ts extensions, which bundler resolution
handles natively).