Title: [Feature]: SSR interactive-directive parity (`bq-model`, `bq-on`) or a documented boundary · Issue #128 · bQuery/bQuery · GitHub
Open Graph Title: [Feature]: SSR interactive-directive parity (`bq-model`, `bq-on`) or a documented boundary · Issue #128 · bQuery/bQuery
X Title: [Feature]: SSR interactive-directive parity (`bq-model`, `bq-on`) or a documented boundary · Issue #128 · bQuery/bQuery
Description: Pre-flight checklist I searched existing issues and did not find a duplicate request. I explained the problem or use case, not just the desired API. Problem or use case renderToString() documents support for a subset of directives (bq-te...
Open Graph Description: Pre-flight checklist I searched existing issues and did not find a duplicate request. I explained the problem or use case, not just the desired API. Problem or use case renderToString() documents s...
X Description: Pre-flight checklist I searched existing issues and did not find a duplicate request. I explained the problem or use case, not just the desired API. Problem or use case renderToString() documents s...
Opengraph URL: https://github.com/bQuery/bQuery/issues/128
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"[Feature]: SSR interactive-directive parity (`bq-model`, `bq-on`) or a documented boundary","articleBody":"**Pre-flight checklist**\n- [x] I searched existing issues and did not find a duplicate request.\n- [x] I explained the problem or use case, not just the desired API.\n\n**Problem or use case**\n`renderToString()` documents support for a subset of directives (`bq-text, bq-html, bq-if, bq-show, bq-for, bq-class, bq-style, bq-bind:*`) and notably **omits the interactive directives `bq-model` and `bq-on`**. A component authored with two-way binding or event handlers therefore renders differently on the server than it behaves on the client, which produces hydration divergence and forces authors to keep two mental models of what works where. This subset behavior is a concrete blocker to `ssr` reaching Stable (#127), because \"renders a directive subset only\" is not a contract teams can build on.\n\n**Proposed solution**\nEither (a) extend server rendering so the full view-directive set produces correct, hydration-ready markup — emitting initial values for `bq-model` and the appropriate hydration markers for `bq-on` so the client can attach listeners on hydrate — or (b) if some directives are intentionally client-only, formalize that as an explicit, enforced, documented boundary with a dev-time warning when an unsupported directive is encountered during SSR. Parity (a) is strongly preferred for the \"one stack\" promise; the explicit boundary (b) is the minimum acceptable outcome.\n\n**Possible API or UX shape**\n```ts\nimport { renderToString } from \"@bquery/bquery/ssr\";\n\n// bq-model emits the current value into the server markup;\n// bq-on emits a hydration marker, listeners attach on hydrate.\nconst html = renderToString(view, {\n directives: \"full\", // \"full\" | \"static\" (current behavior)\n onUnsupportedDirective: \"warn\" // \"warn\" | \"throw\" | \"ignore\"\n});\n```\n\n**Alternatives considered**\nDocumenting the omission in prose only (status quo) — insufficient, because it is silent at runtime and surfaces as confusing hydration bugs. Asking users to avoid `bq-model`/`bq-on` in SSR components — defeats the purpose of a unified client/server view layer and has no parity in Svelte/Vue, both of which render their binding and event constructs server-side.\n\n**Relevant area**\n`ssr`\n\n**Additional context**\nHydration correctness depends on this: today `verifyHydration` only warns in dev (see #130). Vue renders `v-model`/`v-on` constructs server-side and reconciles on hydration; Svelte does the same for `bind:`/`on:`. Closing this gap is what makes bQuery's SSR comparable rather than a static-render subset.\n","author":{"url":"https://github.com/JosunLP","@type":"Person","name":"JosunLP"},"datePublished":"2026-06-26T21:24:58.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/128/bQuery/issues/128"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:74059b61-a698-3fc6-7a33-1ceefe60d5d9 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | DDBC:3217ED:F72619:1511C0B:6A4DD700 |
| html-safe-nonce | 1dd6855115f51bfffac7dc8bcda98a57678d15b02569194d1bcf97a4b5c9ab29 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJEREJDOjMyMTdFRDpGNzI2MTk6MTUxMUMwQjo2QTRERDcwMCIsInZpc2l0b3JfaWQiOiIzMTQzMjc0OTAxMTQ3NjA0NzM2IiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | 7ffbbf88577b8dbf34beaeea0e15e497ee9d11eefdaa51c5e5cf3360c4386994 |
| hovercard-subject-tag | issue:4755235712 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/bQuery/bQuery/128/issue_layout |
| twitter:image | https://opengraph.githubassets.com/0a0c5868d8f910df40c9f70f9dd860e2d2cf71c1e96b67cf10f4623ffac03d21/bQuery/bQuery/issues/128 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/0a0c5868d8f910df40c9f70f9dd860e2d2cf71c1e96b67cf10f4623ffac03d21/bQuery/bQuery/issues/128 |
| og:image:alt | Pre-flight checklist I searched existing issues and did not find a duplicate request. I explained the problem or use case, not just the desired API. Problem or use case renderToString() documents s... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | JosunLP |
| hostname | github.com |
| expected-hostname | github.com |
| None | 06b8a6144231bf3a234f1c2e9993861e07ce98a905912b114aa386c2d7e84b33 |
| turbo-cache-control | no-preview |
| go-import | github.com/bQuery/bQuery git https://github.com/bQuery/bQuery.git |
| octolytics-dimension-user_id | 256381806 |
| octolytics-dimension-user_login | bQuery |
| octolytics-dimension-repository_id | 1139284244 |
| octolytics-dimension-repository_nwo | bQuery/bQuery |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 1139284244 |
| octolytics-dimension-repository_network_root_nwo | bQuery/bQuery |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 1d344bdb7547fe6bca17a59bb2b8aac3dc9532a0 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width