A JSX-style prop={expr} on a component tag is not parsed as an expression. stx documents :prop="expr" for this, but the failure is silent and takes two forms, one of which loses the prop entirely. packages/components/examples/form-examples.stx uses the syntax today, so the shipped example is affected.
Found while fixing the silent <script server> failures in ffeaec7058.
What happens
From packages/components/examples/form-examples.stx:123:
<Form
id="profileForm"
initialValues={{
name: 'John Doe',
email: 'john@example.com',
bio: 'Web developer and designer',
notifications: true
}}
onSubmit={handleEditProfile}
className="space-y-4"
>Measured by logging context.props when Form's server script runs:
{"id":"profileForm","className":"space-y-4"}- A multi-line
=prop is dropped entirely.initialValuesnever reaches the component, so the form renders with no initial values. - A single-line
={expr}prop arrives as a literal string, braces included. The other form on the same page passesonSubmit={handleMultiStepSubmit}and the component receives"onSubmit":"{handleMultiStepSubmit}"— a string where a handler is expected.
Nothing warns in either case.
It also corrupts the render context
The object literal is split across whitespace into separate context keys:
initialValues, name:, 'John, Doe',, email:, 'john@example.com',,
bio:, 'Web, developer, and, designer',, notifications:, true, }}, onSubmit, ...Those fragments become candidate parameter names for the generated <script server> function. One of them, true, is identifier-shaped but reserved, and it threw before the script body ran — which silently dropped the server script of six shipped components (Button, TextInput, EmailInput, Textarea, Form, Checkbox) into static extraction on every render.
That part is fixed in ffeaec7058: a malformed attribute can no longer take down a whole server script. The prop data loss and the context pollution above are not fixed, and are what this issue is about.
Two decisions
- Should
prop={expr}be supported? It is what someone coming from JSX writes. If yes, it needs parsing as an expression, including across lines. If no, it should be a build/dev-time error rather than a dropped prop and a shattered context. - The example should be corrected either way, since it currently demonstrates syntax that does not work:
:initialValues="{ ... }"and@submit="handleEditProfile".
Note that packages/components/examples/form-examples.stx is used as a perf fixture in #1945 measurements, so changing it shifts those numbers.
Repro
bun -e '
const { renderView } = await import("./packages/stx/src/build-views")
await renderView("packages/components/examples/form-examples.stx", {}, { componentsDir: "packages/components/src/ui" })
'Log context.props in extractVariables for form/form.stx, or add a <script server> to any component and pass it a prop=.
🤖 Generated with Claude Code