diff --git a/.changeset/famous-dingos-run.md b/.changeset/famous-dingos-run.md
new file mode 100644
index 0000000000..5726788b91
--- /dev/null
+++ b/.changeset/famous-dingos-run.md
@@ -0,0 +1,5 @@
+---
+"@marko/runtime-tags": patch
+---
+
+Fix adjacent bound values
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/.name-cache.json b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/.name-cache.json
new file mode 100644
index 0000000000..fe850c3449
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/.name-cache.json
@@ -0,0 +1,20 @@
+{
+ "vars": {
+ "props": {
+ "$_$": "t",
+ "$init": "a",
+ "$_expr_input_count1_input_count1Change": "n",
+ "$_count2_effect": "o",
+ "$_count2": "e",
+ "$_count_effect": "i",
+ "$_count$1": "r",
+ "$_input_count1_": "c",
+ "$_count": "m",
+ "$_expr_input_count2_input_count2Change": "s",
+ "$_count2$1": "f",
+ "$_input_count2_": "u",
+ "$_expr_input_count2Change_input_count": "d",
+ "$_expr_input_count1Change_input_count": "l"
+ }
+ }
+}
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/csr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/csr-sanitized.expected.md
new file mode 100644
index 0000000000..7d32b83fad
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/csr-sanitized.expected.md
@@ -0,0 +1,60 @@
+# Render {}
+```html
+
+ 0
+
+
+ 0
+
+
+ 0 0
+
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 1
+
+
+ 1
+
+
+ 1 1
+
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 2
+
+
+ 2
+
+
+ 2 2
+
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 3
+
+
+ 3
+
+
+ 3 3
+
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/csr.expected.md b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/csr.expected.md
new file mode 100644
index 0000000000..77bd86e22a
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/csr.expected.md
@@ -0,0 +1,89 @@
+# Render {}
+```html
+
+ 0
+
+
+ 0
+
+
+ 0 0
+
+```
+
+# Mutations
+```
+inserted button0, button1, div2
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 1
+
+
+ 1
+
+
+ 1 1
+
+```
+
+# Mutations
+```
+div2/#text0: "0" => "1"
+button0/#text0: "0" => "1"
+div2/#text2: "0" => "1"
+button1/#text0: "0" => "1"
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 2
+
+
+ 2
+
+
+ 2 2
+
+```
+
+# Mutations
+```
+div2/#text0: "1" => "2"
+button0/#text0: "1" => "2"
+div2/#text2: "1" => "2"
+button1/#text0: "1" => "2"
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 3
+
+
+ 3
+
+
+ 3 3
+
+```
+
+# Mutations
+```
+div2/#text0: "2" => "3"
+button0/#text0: "2" => "3"
+div2/#text2: "2" => "3"
+button1/#text0: "2" => "3"
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/tags/2counters.js b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/tags/2counters.js
new file mode 100644
index 0000000000..23ab7caeca
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/tags/2counters.js
@@ -0,0 +1,48 @@
+export const _template_ = " ";
+export const _walks_ = /* get, next(1), get, out(1), get, next(1), get, out(1) */" D l D l";
+export const _setup_ = () => {};
+import * as _$ from "@marko/runtime-tags/debug/dom";
+const _expr_input_count2_input_count2Change = /* @__PURE__ */_$.intersection(2, _scope => {
+ const {
+ input_count2,
+ input_count2Change
+ } = _scope;
+ _count2(_scope, input_count2, input_count2Change);
+});
+const _expr_input_count1_input_count1Change = /* @__PURE__ */_$.intersection(2, _scope => {
+ const {
+ input_count1,
+ input_count1Change
+ } = _scope;
+ _count(_scope, input_count1, input_count1Change);
+});
+const _count2_effect = _$.effect("__tests__/tags/2counters.marko_0_count2", (_scope, {
+ count2
+}) => _$.on(_scope["#button/2"], "click", function () {
+ _count2(_scope, count2 + 1), count2;
+}));
+const _count2 = /* @__PURE__ */_$.state("count2", (_scope, count2) => {
+ _$.data(_scope["#text/3"], count2);
+ _count2_effect(_scope);
+});
+const _count_effect = _$.effect("__tests__/tags/2counters.marko_0_count1", (_scope, {
+ count1
+}) => _$.on(_scope["#button/0"], "click", function () {
+ _count(_scope, count1 + 1), count1;
+}));
+const _count = /* @__PURE__ */_$.state("count1", (_scope, count1) => {
+ _$.data(_scope["#text/1"], count1);
+ _count_effect(_scope);
+});
+export const _input_count2Change_ = /* @__PURE__ */_$.value("input_count2Change", 0, () => _expr_input_count2_input_count2Change);
+export const _input_count2_ = /* @__PURE__ */_$.value("input_count2", 0, () => _expr_input_count2_input_count2Change);
+export const _input_count1Change_ = /* @__PURE__ */_$.value("input_count1Change", 0, () => _expr_input_count1_input_count1Change);
+export const _input_count1_ = /* @__PURE__ */_$.value("input_count1", 0, () => _expr_input_count1_input_count1Change);
+export const _input_ = /* @__PURE__ */_$.value("input", (_scope, input) => {
+ _input_count1_(_scope, input.count1);
+ _input_count1Change_(_scope, input.count1Change);
+ _input_count2_(_scope, input.count2);
+ _input_count2Change_(_scope, input.count2Change);
+}, () => _$.intersections([_input_count1_, _input_count1Change_, _input_count2_, _input_count2Change_]));
+export const _params__ = /* @__PURE__ */_$.value("_params_", (_scope, _params_) => _input_(_scope, _params_[0]), () => _input_);
+export default /* @__PURE__ */_$.createTemplate("__tests__/tags/2counters.marko", _template_, _walks_, _setup_, void 0, () => _params__);
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.hydrate.js b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.hydrate.js
new file mode 100644
index 0000000000..a611ec7c84
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.hydrate.js
@@ -0,0 +1,52 @@
+// size: 640 (min) 243 (brotli)
+const _expr_input_count2_input_count2Change = _$.intersection(2, (_scope) => {
+ const { 8: input_count2, 9: input_count2Change } = _scope;
+ _count2$1(_scope, input_count2, input_count2Change);
+ }),
+ _expr_input_count1_input_count1Change = _$.intersection(2, (_scope) => {
+ const { 6: input_count1, 7: input_count1Change } = _scope;
+ _count$1(_scope, input_count1, input_count1Change);
+ }),
+ _count2_effect = _$.effect("a0", (_scope, { 11: count2 }) =>
+ _$.on(_scope[2], "click", function () {
+ _count2$1(_scope, count2 + 1);
+ }),
+ ),
+ _count2$1 = _$.state(11, (_scope, count2) => {
+ _$.data(_scope[3], count2), _count2_effect(_scope);
+ }),
+ _count_effect = _$.effect("a1", (_scope, { 10: count1 }) =>
+ _$.on(_scope[0], "click", function () {
+ _count$1(_scope, count1 + 1);
+ }),
+ ),
+ _count$1 = _$.state(10, (_scope, count1) => {
+ _$.data(_scope[1], count1), _count_effect(_scope);
+ }),
+ _input_count2_ = _$.value(8, 0, () => _expr_input_count2_input_count2Change),
+ _input_count1_ = _$.value(6, 0, () => _expr_input_count1_input_count1Change),
+ _count2 = _$.state(
+ 4,
+ (_scope, count2) => {
+ _$.data(_scope[2], count2), _input_count2_(_scope[0], count2);
+ },
+ () => _$.inChild(0, _input_count2_),
+ ),
+ _count = _$.state(
+ 3,
+ (_scope, count1) => {
+ _$.data(_scope[1], count1), _input_count1_(_scope[0], count1);
+ },
+ () => _$.inChild(0, _input_count1_),
+ );
+_$.register("b0", function (_scope) {
+ return (_new_count) => {
+ _count(_scope, _new_count);
+ };
+}),
+ _$.register("b1", function (_scope) {
+ return (_new_count2) => {
+ _count2(_scope, _new_count2);
+ };
+ }),
+ init();
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.js
new file mode 100644
index 0000000000..05056ee700
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/dom.expected/template.js
@@ -0,0 +1,32 @@
+export const _template_ = `${_counters_template}
`;
+export const _walks_ = /* beginChild, _counters_walks, endChild, next(1), replace, over(2), replace, out(1) */`/${_counters_walks}&D%c%l`;
+import { _setup_ as _counters, _input_count1_ as _counters_input_count, _input_count1Change_ as _counters_input_count1Change, _input_count2Change_ as _counters_input_count2Change, _input_count2_ as _counters_input_count2, _template_ as _counters_template, _walks_ as _counters_walks } from "./tags/2counters.marko";
+import * as _$ from "@marko/runtime-tags/debug/dom";
+const _count2 = /* @__PURE__ */_$.state("count2", (_scope, count2) => {
+ _$.data(_scope["#text/2"], count2);
+ _counters_input_count2(_scope["#childScope/0"], count2);
+}, () => _$.inChild("#childScope/0", _counters_input_count2));
+const _count = /* @__PURE__ */_$.state("count1", (_scope, count1) => {
+ _$.data(_scope["#text/1"], count1);
+ _counters_input_count(_scope["#childScope/0"], count1);
+}, () => _$.inChild("#childScope/0", _counters_input_count));
+export function _setup_(_scope) {
+ _counters(_scope["#childScope/0"]);
+ _count(_scope, 0);
+ _count2(_scope, 0);
+ _counters_input_count1Change(_scope["#childScope/0"], _count1Change(_scope));
+ _counters_input_count2Change(_scope["#childScope/0"], _count2Change(_scope));
+}
+function _count1Change(_scope) {
+ return _new_count => {
+ _count(_scope, _new_count);
+ };
+}
+function _count2Change(_scope) {
+ return _new_count2 => {
+ _count2(_scope, _new_count2);
+ };
+}
+_$.register("__tests__/template.marko_0/count1Change", _count1Change);
+_$.register("__tests__/template.marko_0/count2Change", _count2Change);
+export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _template_, _walks_, _setup_);
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/html.expected/tags/2counters.js b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/html.expected/tags/2counters.js
new file mode 100644
index 0000000000..05dee9f05b
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/html.expected/tags/2counters.js
@@ -0,0 +1,20 @@
+import * as _$ from "@marko/runtime-tags/debug/html";
+const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
+ const _scope0_id = _$.nextScopeId();
+ const count1 = input.count1;
+ const count2 = input.count2;
+ _$.write(`${_$.escapeXML(count1)}${_$.markResumeNode(_scope0_id, "#text/1")} ${_$.markResumeNode(_scope0_id, "#button/0")}${_$.escapeXML(count2)}${_$.markResumeNode(_scope0_id, "#text/3")} ${_$.markResumeNode(_scope0_id, "#button/2")}`);
+ _$.writeEffect(_scope0_id, "__tests__/tags/2counters.marko_0_count2");
+ _$.writeEffect(_scope0_id, "__tests__/tags/2counters.marko_0_count1");
+ _$.writeScope(_scope0_id, {
+ "input_count1": input.count1,
+ "input_count1Change": input.count1Change,
+ "input_count2": input.count2,
+ "input_count2Change": input.count2Change,
+ "count1": count1,
+ "count2": count2,
+ "count1@": input.count1Change,
+ "count2@": input.count2Change
+ });
+});
+export default /* @__PURE__ */_$.createTemplate("__tests__/tags/2counters.marko", _renderer);
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/html.expected/template.js b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/html.expected/template.js
new file mode 100644
index 0000000000..4063ae6061
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/html.expected/template.js
@@ -0,0 +1,23 @@
+import _counters from "./tags/2counters.marko";
+import * as _$ from "@marko/runtime-tags/debug/html";
+const _renderer = /* @__PURE__ */_$.createRenderer((input, _tagVar) => {
+ const _scope0_id = _$.nextScopeId();
+ const count1 = 0;
+ const count2 = 0;
+ const _childScope = _$.peekNextScope();
+ _counters({
+ count1: count1,
+ count1Change: _$.register(_new_count => {
+ count1 = _new_count;
+ }, "__tests__/template.marko_0/count1Change", _scope0_id),
+ count2Change: _$.register(_new_count2 => {
+ count2 = _new_count2;
+ }, "__tests__/template.marko_0/count2Change", _scope0_id),
+ count2: count2
+ });
+ _$.write(`${_$.escapeXML(count1)}${_$.markResumeNode(_scope0_id, "#text/1")} ${_$.escapeXML(count2)}${_$.markResumeNode(_scope0_id, "#text/2")}
`);
+ _$.writeScope(_scope0_id, {
+ "#childScope/0": _$.writeExistingScope(_childScope)
+ });
+});
+export default /* @__PURE__ */_$.createTemplate("__tests__/template.marko", _renderer);
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/resume-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/resume-sanitized.expected.md
new file mode 100644
index 0000000000..7d32b83fad
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/resume-sanitized.expected.md
@@ -0,0 +1,60 @@
+# Render {}
+```html
+
+ 0
+
+
+ 0
+
+
+ 0 0
+
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 1
+
+
+ 1
+
+
+ 1 1
+
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 2
+
+
+ 2
+
+
+ 2 2
+
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+ 3
+
+
+ 3
+
+
+ 3 3
+
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/resume.expected.md b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/resume.expected.md
new file mode 100644
index 0000000000..bd81837d8b
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/resume.expected.md
@@ -0,0 +1,157 @@
+# Render {}
+```html
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+ 0
+
+
+
+
+
+```
+
+# Mutations
+```
+
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+
+ 1
+
+
+
+ 1
+
+
+
+
+
+```
+
+# Mutations
+```
+#document/html0/body1/div4/#text0: "0" => "1"
+#document/html0/body1/button0/#text0: "0" => "1"
+#document/html0/body1/div4/#text4: "0" => "1"
+#document/html0/body1/button2/#text0: "0" => "1"
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+
+
+ 2
+
+
+
+
+ 2
+
+
+
+
+ 2
+
+
+
+ 2
+
+
+
+
+
+```
+
+# Mutations
+```
+#document/html0/body1/div4/#text0: "1" => "2"
+#document/html0/body1/button0/#text0: "1" => "2"
+#document/html0/body1/div4/#text4: "1" => "2"
+#document/html0/body1/button2/#text0: "1" => "2"
+```
+
+
+# Render
+container.querySelectorAll("button").forEach(item => item.click())
+
+```html
+
+
+
+ 3
+
+
+
+
+ 3
+
+
+
+
+ 3
+
+
+
+ 3
+
+
+
+
+
+```
+
+# Mutations
+```
+#document/html0/body1/div4/#text0: "2" => "3"
+#document/html0/body1/button0/#text0: "2" => "3"
+#document/html0/body1/div4/#text4: "2" => "3"
+#document/html0/body1/button2/#text0: "2" => "3"
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/ssr-sanitized.expected.md b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/ssr-sanitized.expected.md
new file mode 100644
index 0000000000..bb1f57d3d7
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/ssr-sanitized.expected.md
@@ -0,0 +1,12 @@
+# Render "End"
+```html
+
+ 0
+
+
+ 0
+
+
+ 0 0
+
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/ssr.expected.md b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/ssr.expected.md
new file mode 100644
index 0000000000..9e6ad64200
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/__snapshots__/ssr.expected.md
@@ -0,0 +1,57 @@
+# Write
+ 0 0 0 0
+
+
+# Render "End"
+```html
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+
+ 0
+
+
+
+
+
+```
+
+# Mutations
+```
+inserted #document/html0
+inserted #document/html0/head0
+inserted #document/html0/body1
+inserted #document/html0/body1/button0
+inserted #document/html0/body1/button0/#text0
+inserted #document/html0/body1/button0/#comment1
+inserted #document/html0/body1/#comment1
+inserted #document/html0/body1/button2
+inserted #document/html0/body1/button2/#text0
+inserted #document/html0/body1/button2/#comment1
+inserted #document/html0/body1/#comment3
+inserted #document/html0/body1/div4
+inserted #document/html0/body1/div4/#text0
+inserted #document/html0/body1/div4/#comment1
+inserted #document/html0/body1/div4/#text2
+inserted #document/html0/body1/div4/#comment3
+inserted #document/html0/body1/div4/#text4
+inserted #document/html0/body1/div4/#comment5
+inserted #document/html0/body1/script5
+inserted #document/html0/body1/script5/#text0
+```
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/tags/2counters.marko b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/tags/2counters.marko
new file mode 100644
index 0000000000..f74997231f
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/tags/2counters.marko
@@ -0,0 +1,5 @@
+
+
+
+${count1}
+${count2}
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/template.marko b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/template.marko
new file mode 100644
index 0000000000..2749b543d7
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/template.marko
@@ -0,0 +1,8 @@
+
+
+
+<2counters count1:=count1 count2:=count2 />
+
+
+ ${count1} ${count2}
+
\ No newline at end of file
diff --git a/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/test.ts b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/test.ts
new file mode 100644
index 0000000000..d50bda6b16
--- /dev/null
+++ b/packages/runtime-tags/src/__tests__/fixtures/multiple-bound-values/test.ts
@@ -0,0 +1,5 @@
+export const steps = [{}, clickAllButtons, clickAllButtons, clickAllButtons];
+
+function clickAllButtons(container: Element) {
+ container.querySelectorAll("button")!.forEach((item) => item.click());
+}
diff --git a/packages/runtime-tags/src/translator/visitors/tag/index.ts b/packages/runtime-tags/src/translator/visitors/tag/index.ts
index 3508b90c35..097d348373 100644
--- a/packages/runtime-tags/src/translator/visitors/tag/index.ts
+++ b/packages/runtime-tags/src/translator/visitors/tag/index.ts
@@ -31,7 +31,7 @@ export default {
}
tag.node.attributes.splice(
- ++i,
+ i + 1,
0,
t.markoAttribute(attr.node.name + "Change", changeValue),
);