diff --git a/site/app/pages/learn/page.zx b/site/app/pages/learn/page.zx index 818c694d..57be6b9f 100644 --- a/site/app/pages/learn/page.zx +++ b/site/app/pages/learn/page.zx @@ -468,7 +468,13 @@ fn Interactivity(allocator: zx.Allocator, props: InteractivityProps) zx.Componen
To update component state in response to events, use ctx.bind(handler) and access state through the event handler:
When you use ctx.bind(), the handler receives a zx.server.Event.Stateful which provides access to component state through event.state(T).
When you use ctx.bind(), the handler receives a zx.client.Event.Stateful which provides access to component state through event.state(T). Call state(T) in the same order as the ctx.state() calls in the component; the types must match.
@rendering={"{.client}"}
+ must be set on the interactive component or a parent that wraps it. Without it, the component renders server-side only and event handlers are ignored.
+ For complex applications, organize your state into structs and pass handlers for different operations:
diff --git a/site/app/pages/reference/page.zx b/site/app/pages/reference/page.zx index 43df86ac..3f1c3354 100644 --- a/site/app/pages/reference/page.zx +++ b/site/app/pages/reference/page.zx @@ -116,6 +116,43 @@ pub fn Page(ctx: zx.PageContext) !zx.Component { // const setup_elapsed_ms = @as(f64, @floatFromInt(setup_elapsed_ns)) / @as(f64, @floatFromInt(std.time.ns_per_ms)); // std.log.info("\x1b[1;36m[DOCS PAGE] Setup phase completed: {d:.3}ms\x1b[0m", .{setup_elapsed_ms}); + const csr_simple_handler_example = + \\fn handleInput(event: zx.client.Event) void { + \\ const value = event.value() orelse ""; + \\ zx.log.info("Input: {s}", .{value}); + \\} + \\// Attach: oninput={handleInput} + ; + + const csr_stateful_handler_example = + \\pub fn Counter(ctx: *zx.ComponentCtx(void)) zx.Component { + \\ const count = ctx.state(i32, 0); + \\ return ( + \\Warning: Only use @escaping={"{.none}"} for content you trust completely. User-provided content should always use the default escaping.
The @rendering attribute enables client-side rendering for interactive components.
The @rendering attribute enables client-side rendering for interactive components. Without it, all components render server-side only and event handlers are not active in the browser.
Values:
.client - Client-side render with Zig (compiles component to WebAssembly).react - Client-side render with React (for imported React/TSX components).client - Client-side render with Zig (compile component to WebAssembly)Use @rendering={"{.client}"} to make a component interactive. The component is server-rendered for the initial HTML, then hydrated and re-rendered client-side on state changes. Only the marked component is managed client-side; the rest of the page stays server-rendered.
Client components that need reactive state must use zx.ComponentCtx(Props) (or zx.ComponentCtx(void) when there are no props). The context provides ctx.state(T, initial) to declare a piece of state:
ctx.state(T, initial_value) - declares a reactive value of type T. Returns a State(T) handle that persists across re-renders.state.get() - read the current value. Can be used directly in markup as {"{count}"}.state.set(new_value) - update the value and trigger a re-render.state.update(fn(T) T) - update via a transform function.State is stored per-component-instance and survives re-renders. On the server (SSR), ctx.state() always returns the initial value.
ZX provides three ways to attach event handlers to client components:
+1. Simple handler - for reading the event without touching state:
+The handler receives a zx.client.Event value. Useful methods:
event.value() - returns ?[]const u8 with event.target.value (for inputs and selects).event.key() - returns ?[]const u8 with the pressed key name (for keyboard events).2. Stateful handler via ctx.bind() - for reading or writing component state:
The handler receives *zx.client.Event.Stateful. Call e.state(T) in the same order as ctx.state() in the component to access each piece of state.
3. State transform via state.bind() - the simplest option when the update is a pure function of the current value:
The transform function takes the current value and returns the new value. No event object is needed.
+ +Use @rendering={"{.react}"} to embed a React or TSX component. Import the component with @jsImport and pass it as you would a ZX component. React handles rendering and hydration on the client.