This page documents high-impact Phoenix-facing APIs used by applications authored in Haxe and compiled to Elixir.
phoenix.Phoenix: canonical LiveView callback result types and helper entrypointsphoenix.Component: assign/slot helper APIs and component-oriented utilitiesphoenix.Phoenix.Socket: LiveView callback socket surface (includes assign helpers via extensions)phoenix.LiveSocket: optional typed wrapper operationsphoenix.PhoenixFlash: typed flash helpersphoenix.Channel+phoenix.channels.*: typed channel callback/result helpersphoenix.Presence+phoenix.PresenceModule: presence tracking APIsphoenix.types.*: typed contracts used by templates, assigns, slots, hooks, and route params
Typical metadata + callback shape:
@:native("MyAppWeb.TodoLive")
@:liveview
class TodoLive {
public static function mount(params:Term, session:Term, socket:Socket<TodoAssigns>):MountResult<TodoAssigns> {
return Ok(socket);
}
@:native("handle_event")
public static function handleEvent(event:String, params:Term, socket:Socket<TodoAssigns>):HandleEventResult<TodoAssigns> {
return NoReply(socket);
}
}Key points:
- Use
@:native("handle_event")when your Haxe method name differs from canonical callback naming. - Prefer typed assigns typedefs and keep them shared between render/mount/event paths.
phoenix.Phoenix.Socket supports Phoenix-faithful runtime semantics with Haxe-oriented authoring ergonomics:
assign(_.field, value)for short single-field updatesassign({ ... })for Phoenix-style bulk updates (assign/2shape)assignKey(keys.field, value)as an optional typed-key modeassignNew/assignNewKeyandupdate/updateKeyfor default/update workflows
merge({ ... }) remains available as a backward-compatible alias; prefer assign({ ... }) for 1:1 Phoenix API shape.
Typed-key setup is now:
var keys = phoenix.AssignKeys.of(MyAssigns)- then
assignKey(keys.field, value)
phoenix.LiveSocket keeps the same APIs for explicit wrapper-style helpers.
Canonical deep dive:
docs/04-api-reference/LIVE_SOCKET_ASSIGN_API.md
@:component semantics are two-level:
- class-level: component module context
- function-level: discoverable component entrypoint
@:native("MyAppWeb.CoreComponents")
@:component
class CoreComponents {
@:component
public static function button(assigns:ButtonAssigns):String {
return <button class={@class}>{@inner_content}</button>;
}
}Slot typing uses phoenix.types.Slot + @:slot metadata in assigns typedefs.
Primary template entrypoints:
- Inline markup:
return <div>...</div>; phoenix.hxx.HeexTemplate(root,root_ast, helpers)HXX.hxx(...)/HXX.block(...)for explicit string-template forms
Relevant strictness/authoring metadata:
@:hxx_mode("balanced"|"tsx"|"metal")@:hxx_no_inline_markup@:allow_heex(escape hatch)@:phxHookNamesfor typed hook-name registries
@:socket+@:socketChannels([...])define topic routing at socket module level@:channelmodules implement join/in/out behaviorphoenix.channels.JoinResultandphoenix.channels.ReplyResultprovide typed callback result contracts
@:presencemarks a presence module@:presenceTopic("...")(optional) supplies default topic wiring for presence helpers- Use
Presence.track,Presence.update, andPresence.listpatterns for stable realtime state
Main test APIs:
phoenix.test.ConnTestphoenix.test.LiveViewTestphoenix.test.LiveViewphoenix.test.Conn
Keep most coverage in Haxe-authored ExUnit integration tests and use Playwright only as thin smoke coverage.
- Missing function-level
@:componenton a component function used as<.name ...> - Ambiguous component names under strict component mode (
-D hxx_strict_components) - Callback naming drift when
@:native("handle_event")is omitted - Untyped slot/let usage under strict slot mode (
-D hxx_strict_slots) - Hook names not registered when strict hook mode is enabled (
-D hxx_strict_phx_hook)
docs/04-api-reference/LIVE_SOCKET_ASSIGN_API.mddocs/04-api-reference/ANNOTATIONS.mddocs/04-api-reference/ROUTER_DSL.mddocs/02-user-guide/HXX_SYNTAX_AND_COMPARISON.mddocs/02-user-guide/INLINE_MARKUP.md