Skip to content

feat(dom): implement true multi-surface DOM rendering#115

Merged
mahyarmlk merged 1 commit into
mainfrom
feat/dom-multi-surface-rendering
Jun 26, 2026
Merged

feat(dom): implement true multi-surface DOM rendering#115
mahyarmlk merged 1 commit into
mainfrom
feat/dom-multi-surface-rendering

Conversation

@mahyarmlk

Copy link
Copy Markdown
Collaborator

Summary

Implements the approved multi-surface DOM rendering from the design proposal at docs/proposals/Dom-Multi-Surface-Rendering.md (PR #114, merge 665f46d).

Before

renderDom rendered only the first surface (screenDef.surfaces[0]) and ignored all others. All asks and actions were rendered into a single <form> inside a single <main>, regardless of which surface they belonged to.

After

  • Each surface renders as a separate <section> with aria-label and unique DOM id
  • Single-surface screens produce identical DOM output (no suffix, no <section> wrapper) — fully backward compatible
  • Multi-surface screens use --<surfaceName> suffixed DOM ids for asks, actions, hints, reasons, and feedback outputs to avoid duplicate ids
  • Each surface renders only the items it contains (asks/actions scoped per surface)
  • Duplicate ask controls (text, checkbox, select) across surfaces share the same underlying state via reactive subscriptions
  • Duplicate action buttons execute the same underlying action
  • Blocked reasons, aria-describedby, Enter key hints, and feedback output are scoped per surface copy
  • data-intent-* semantic ids remain identical across duplicate copies
  • Resources are not rendered as surface items

Changed files

File Change
packages/dom/src/index.ts Refactored buildDom into helpers (buildSurface, buildForm, buildAskControl, buildActionButton), per-surface subscriptions, state sync
packages/dom/src/dom.test.ts Added 16 multi-surface tests
docs/proposals/Dom-Multi-Surface-Rendering.md Updated status to "Implemented"
.changeset/many-experts-chew.md Patch changeset for @intent-framework/dom

Tests added

  1. Multiple surfaces render as separate sections
  2. Single-surface DOM ids remain backward compatible
  3. Multi-surface ask/action ids are suffixed
  4. Each surface renders only its own items
  5. Duplicate text ask controls share state
  6. Duplicate checkbox ask controls share state and checked value
  7. Duplicate select ask controls share state and selected value
  8. Duplicate action buttons execute the same action
  9. Enabled/disabled state updates across duplicate action buttons
  10. Blocked reasons are scoped per surface copy
  11. aria-describedby points to the correct per-surface reason/hint ids
  12. Per-surface feedback output exists and is aria-live
  13. Enter key default action works per surface for text-like controls
  14. Enter key does not execute from checkbox/select
  15. data-intent-* semantic ids remain identical across duplicate surface copies
  16. cleanup unsubscribes all multi-surface listeners

Validation

All passed:

  • pnpm test — 322 tests across all packages and examples
  • pnpm typecheck — no errors
  • pnpm build — clean build
  • pnpm lint — no errors
  • pnpm pack:check — packages packable
  • pnpm changeset status — correct

Semantics note

Feedback: when the same action appears in multiple surfaces and executes, both surfaces' <output> elements show the feedback message (the status change subscription updates all copies). This is the "all copies" behavior and is consistent with the shared-action design.

Do not merge automatically

This changes DOM runtime behavior. Requires review.

Each surface renders as a separate <section> with accessible label and
unique DOM id. Multi-surface screens use --<surfaceName> suffixed DOM
ids for asks, actions, hints, reasons, and feedback outputs to avoid
duplicates. Single-surface screens preserve backward-compatible DOM
output (no suffix, no section wrapper).

Duplicate ask controls across surfaces share underlying state via
reactive subscriptions. Duplicate action buttons execute the same
action. Blocked reasons, aria-describedby, Enter key hints, and
feedback output are scoped per surface copy.

16 new tests cover multi-surface sectioning, id suffixing, item
scoping, shared state (text/checkbox/select), shared actions,
enabled/disabled sync, scoped blocked reasons, scoped aria-describedby,
per-surface feedback, Enter key per surface, semantic id preservation,
and cleanup.
@mahyarmlk mahyarmlk merged commit 2185136 into main Jun 26, 2026
1 check passed
@mahyarmlk mahyarmlk deleted the feat/dom-multi-surface-rendering branch June 26, 2026 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant