10 KiB
API Reference
Complete reference for all public LiveSvelte APIs.
Elixir API
LiveSvelte.svelte/1
Renders a Svelte component in a LiveView template.
<.svelte name="Counter" props={%{count: @count}} socket={@socket} />
Attributes:
| Attribute | Type | Default | Required | Description |
|---|---|---|---|---|
name |
string |
— | ✓ | Component name (filename without .svelte, relative to assets/svelte/) |
props |
map |
%{} |
Props to pass to the component | |
socket |
map |
nil |
LiveView socket — required when ssr: true |
|
id |
string |
auto | Stable DOM id override | |
key |
any |
nil |
Identity key for DOM id generation in loops | |
class |
string |
nil |
CSS class on the wrapper div | |
ssr |
boolean |
true |
Enable SSR for this component | |
diff |
boolean |
true |
Enable props diffing (requires enable_props_diff: true in config) |
|
:loading slot |
Content shown while component loads (only with ssr={false}) |
|||
:inner_block slot |
Inner content (passed to Svelte as a slot) |
Name examples:
Counter.svelte → name="Counter"
forms/UserForm.svelte → name="forms/UserForm"
~V Sigil
Inline Svelte template as a LiveView render macro.
def render(assigns) do
~V"""
<script>
let { count } = $props()
</script>
<p>Count: {count}</p>
"""
end
All LiveView assigns are automatically available as props. The template is written to assets/svelte/_build/MyModule.svelte at compile time.
LiveSvelte.Components
Auto-generated shorthand component functions based on discovered .svelte files.
# In web module html_helpers:
use LiveSvelte.Components
# In templates — instead of <.svelte name="Counter" ...>:
<.Counter count={@count} socket={@socket} />
Counter.svelte → <.Counter>, forms/UserForm.svelte → <.forms_UserForm> (slashes converted to underscores).
LiveSvelte.Test.get_svelte/1,2
Inspect Svelte component props from HTML in tests.
import LiveSvelte.Test
# Get first component in HTML
component = get_svelte(html)
# Get component by name
component = get_svelte(html, name: "Counter")
# Get component by DOM id
component = get_svelte(html, id: "Counter-1")
# Get directly from a LiveView
{:ok, view, _html} = live(conn, "/counter")
component = get_svelte(view, name: "Counter")
Returns a map with:
name— component name stringid— DOM id of the wrapper elementprops— decoded props map (string keys)slots— map of slot name → HTML stringssr— boolean, whether SSR was active
Example:
{:ok, _view, html} = live(conn, "/counter")
component = get_svelte(html, name: "Counter")
assert component.props["count"] == 0
LiveSvelte.Encoder Protocol
Protocol for encoding custom structs as JSON props. Implement it directly or use @derive:
# Simple derive — exposes all public fields
@derive LiveSvelte.Encoder
defstruct [:id, :name]
# Restricted derive — only expose listed fields
@derive {LiveSvelte.Encoder, only: [:id, :name, :email]}
defstruct [:id, :name, :email, :password_hash]
# Excluded fields derive
@derive {LiveSvelte.Encoder, except: [:password_hash]}
defstruct [:id, :name, :email, :password_hash]
Without @derive, passing a struct as a prop will raise an error.
LiveSvelte.Reload / vite_assets/1
With phoenix_vite: The layout uses PhoenixVite.Components.assets; ensure config/dev.exs has the endpoint’s static_url: [host: "localhost", port: 5173] and watchers: [..., vite: {PhoenixVite.Npm, :run, [:vite, ~w(dev)]}] so the Vite dev server runs and HMR works. The Igniter installer adds these.
Without phoenix_vite: Use LiveSvelte.Reload.vite_assets/1 in your layout. HMR helper for development; includes the Vite dev server client script.
<!-- In root layout, development only -->
<%= if Application.get_env(:live_svelte, :ssr_module) == LiveSvelte.SSR.ViteJS do %>
<LiveSvelte.Reload.vite_assets path="/assets/js/app.js" />
<% end %>
JavaScript API
getHooks(Components)
Entry point. Returns a hooks map to pass to LiveSocket:
import { getHooks } from "live_svelte"
import Components from "virtual:live-svelte-components"
const liveSocket = new LiveSocket("/live", Socket, {
hooks: getHooks(Components),
params: { _csrf_token: csrfToken }
})
useLiveSvelte()
Access the Phoenix hook context from any LiveSvelte-mounted component.
import { useLiveSvelte } from "live_svelte"
<script>
import { useLiveSvelte } from "live_svelte"
const { pushEvent, pushEventTo, live } = useLiveSvelte()
function save(data) {
pushEvent("save", data)
}
function saveWithReply(data) {
pushEvent("save", data, (reply) => console.log(reply))
}
</script>
Returns:
live— raw Phoenix hook contextpushEvent(event, payload, callback?)— push event to LiveViewpushEventTo(target, event, payload, callback?)— push event to specific LiveView
useLiveEvent(event, callback)
Subscribe to a server-sent LiveView event. Automatically cleans up on component destroy.
<script>
import { useLiveEvent } from "live_svelte"
useLiveEvent("item_added", (payload) => {
console.log("New item:", payload)
})
</script>
useLiveConnection()
Reactive WebSocket connection state.
<script>
import { useLiveConnection } from "live_svelte"
const conn = useLiveConnection()
</script>
{#if !conn.connected}
<div class="banner">Reconnecting...</div>
{/if}
Returns:
connected—boolean, reactive
useLiveNavigation()
Client-side LiveView navigation.
<script>
import { useLiveNavigation } from "live_svelte"
const { patch, navigate } = useLiveNavigation()
</script>
<button onclick={() => patch("?page=2")}>Next page</button>
<button onclick={() => navigate("/other")}>Navigate</button>
Returns:
patch(hrefOrParams, opts?)— patch current LiveView (triggershandle_params/3)navigate(href, opts?)— navigate to a new LiveView
Both accept { replace: true } to use history.replaceState.
useLiveForm(formFn, opts?)
Reactive form binding with Ecto changeset support. See Forms and Validation for full documentation.
import { useLiveForm } from "live_svelte"
<script>
import { useLiveForm } from "live_svelte"
let { form } = $props()
const { field, fieldArray } = useLiveForm(() => form)
</script>
Parameters:
formFn— getter function returning the form propopts?—{ changeEvent?, submitEvent?, debounceInMilliseconds? }
Returns:
field(name)— field descriptor withname,value,error,phx-debouncefieldArray(name)— array field withfields,append,prepend,remove
useLiveUpload(uploadConfig, options)
File upload integration. See File Uploads for full documentation.
import { useLiveUpload } from "live_svelte"
<script>
import { useLiveUpload } from "live_svelte"
let { uploads } = $props()
const { showFilePicker, entries, submit, cancel, sync } = useLiveUpload(
uploads.avatar,
{ changeEvent: "validate", submitEvent: "submit" }
)
$effect(() => sync(uploads.avatar))
</script>
Parameters:
uploadConfig— the upload config object (e.g.uploads.avatar), passed directly not as a getteroptions—{ changeEvent?: string, submitEvent: string }—submitEventis required
Returns:
showFilePicker()— open file picker dialogaddFiles(files)— enqueue files fromFile[]orDataTransfer(drag-drop)entries—Readable<UploadEntry[]>store — use$entriesin templatesprogress—Readable<number>— overall progress 0–100valid—Readable<boolean>— true when no top-level upload errorssubmit()— programmatic form submitcancel(ref?)— cancel entry by ref string, or all when omittedclear()— reset file inputsync(config)— merge updated config from server; call in$effect
useEventReply()
Request-response pattern: push an event and await a reply.
import { useEventReply } from "live_svelte"
<script>
import { useEventReply } from "live_svelte"
const { push } = useEventReply()
async function save(data) {
const result = await push("save", data)
console.log("Server replied:", result)
}
</script>
Returns:
push(event, payload)— returns aPromisethat resolves with the server reply
The LiveView must reply using {:reply, payload, socket} in handle_event/3:
def handle_event("save", params, socket) do
{:reply, %{status: "ok"}, socket}
end
Link Component
Client-side navigation component. Svelte equivalent of Phoenix's <.link>.
<script>
import { Link } from "live_svelte"
</script>
<Link href="/other-page">Go to other page</Link>
<Link href="/other-page" replace={true}>Replace history</Link>
Telemetry Events
| Event | Measurements | Metadata | Description |
|---|---|---|---|
[:live_svelte, :ssr, :start] |
%{system_time: integer} |
%{component: name} |
SSR render begins |
[:live_svelte, :ssr, :stop] |
%{duration_microseconds: integer} |
%{component: name} |
SSR render completes |
[:live_svelte, :ssr, :exception] |
%{system_time: integer} |
%{component: name, reason: term} |
SSR render fails |
Configuration Keys
See Configuration for full details.
| Key | Default | Description |
|---|---|---|
config :live_svelte, :ssr |
true |
Global SSR enable/disable |
config :live_svelte, :ssr_module |
LiveSvelte.SSR.NodeJS |
SSR module |
config :live_svelte, :json_library |
LiveSvelte.JSON |
JSON encoder |
config :live_svelte, :enable_props_diff |
true |
Props diffing system |
config :live_svelte, :gettext_backend |
nil |
Gettext for form errors |
config :live_svelte, :vite_host |
"http://localhost:5173" |
Vite dev server URL |