gsx supports JavaScript-valued attributes, script interpolation, and JSON data islands. Use explicit JavaScript literals in attributes so code is distinguishable from ordinary text.
Use a js`...` literal for a handler or JavaScript expression:
Inside the literal, @{ expr } inserts a Go value at a JavaScript value,
string, or regular-expression position. Use js"..." when the JavaScript itself
contains backticks. See Attributes
for literal syntax and Escaping for
the trust boundary.
A hole in a JavaScript binding position — an assignment target, or a
declaration or member name — must have type gsx.RawJS; it is spliced verbatim.
Any other type there is a compile error, since a value would be JSON-quoted and
break the code. Wrap the trusted expression in gsx.RawJS(...) to assign to a
dynamic path:
::: v-pre
component Bind(path string) {
<input @change=js`@{gsx.RawJS(path)} = $event.target.value;`/>
}:::
Keep a js or css literal with @{} holes on the native element that
consumes it. A wrapper should accept ordinary parameters and build the contextual
literal at that destination:
component SaveButton(id string) {
<button @click=js`save(@{id})`>Save</button>
}
<SaveButton id={id}/>On a component tag, an unbraced, hole-free contextual literal may fall through as authored text. The same unbraced form is rejected when it contains holes.
In a Go expression, a js literal has type gsx.RawJS and a css literal has
type gsx.RawCSS. Store them in a local variable when a contextual value must
be assembled before it reaches the native element:
::: v-pre
component Choice(id int, color string) {
{{
behavior := js`select(@{id})`
styles := css`color:@{color}`
}}
<button @click={behavior} style={styles}>Select</button>
}:::
Each hole follows the JavaScript or CSS rules for its position before the typed
value is created. Trusted gsx.RawJS and gsx.RawCSS holes retain their
documented passthrough; see Escaping. Do
not render the literal directly as visible body text.
A component may explicitly accept the trusted type. Use braces so the literal binds the declared parameter as a Go expression:
component Widget(Handler gsx.RawJS, Rule gsx.RawCSS) {
<button @click={Handler} style={Rule}>Go</button>
}
<Widget Handler={js`open(@{id})`} Rule={css`width:@{width}px`}/>::: v-pre
Because the literal is a Go value, its holes cannot use an error-returning
pipeline or renderer. Top-level declarations also cannot use a filter or
renderer that takes ctx; component expressions and {{ }} blocks can.
:::
Alpine directive values are JavaScript expressions, so mark x-data, x-model,
x-for, x-text, @click, and :key values with js. The same form works for
htmx attributes that contain JavaScript.
JSON is a subset of JavaScript, so attributes such as htmx's hx-vals use the
same literal:
Go strings, numbers, structs, maps, and slices in value-position holes are encoded as JSON values. The rendered attribute is then HTML-escaped; the browser restores the JSON text before the consumer reads it. Name keys in the literal and place dynamic holes in value positions.
When the entire attribute value is a single hole — data-labels=js@{labels} — gsx JSON-encodes the whole Go value, so chart `data-*` attributes and a whole-value `hx-vals` need no hand-built JSON. A hole that is *not* the whole value and sits before a token (`js`@{x} = 1, js@{x} + 2``) is a
binding/operand position and accepts only gsx.RawJS. This applies to `js`
attributes; a plain `{ … }` attribute still takes only a string/number/bool.
Inside <script>, @{ expr } inserts a Go value in the surrounding JavaScript
context:
Value-position interpolation produces JSON notation. String and
regular-expression positions receive their matching escapes, including escapes
that prevent input from ending the <script> element. gsx.RawJS bypasses
those protections and is only for JavaScript you trust; see
Escaping.
Use <script type="application/json"> to expose server data without executing
it. Interpolation encodes the Go value as JSON, and client code can read the
element's text content and pass it to JSON.parse.