Looking for practical examples? Check out Basic Usage for common patterns and Quickstart for your first component.
Overview
LiveVue bridges two different paradigms: Phoenix LiveView with its server-side state management and HTML over WebSockets, and Vue.js with its client-side reactivity and virtual DOM. The challenge is making these two systems work together seamlessly while maintaining the benefits of both.Component lifecycle
Server-side rendering (SSR)
When a LiveView renders a Vue component, LiveVue generates a specialdiv element with component configuration stored in data attributes. Here’s what the server generates:
Client-side hydration
When the page loads and Phoenix LiveView connects, theVueHook activates. Here’s the simplified flow from hooks.ts:
- Resolves the component name to the actual Vue component
- Makes props and slots reactive using Vue’s reactivity system
- Mounts the Vue component (optionally hydrating existing SSR content)
- Configures event handlers for bidirectional communication
Reactive updates
When server state changes, LiveView sends new data via WebSocket:- Phoenix updates only the changed data attributes
- Vue’s reactivity system automatically detects these changes
- Only affected parts of the Vue component re-render
updated() hook:
Props diffing system
LiveVue implements an efficient diffing system that minimizes data transmission by sending only changed properties as JSON patches.Server-side diff construction
Change detection LiveView’s__changed__ tracking system identifies which assigns have been modified since the last render. For simple value changes, __changed__ contains true for the changed key. For complex data structures (maps, lists, structs), it stores the previous value to enable deep diffing.
Struct encoding
Before diffing can occur, any custom structs are converted to maps using the LiveVue.Encoder protocol:
- Simple values (strings, numbers, booleans): Generate a direct “replace” operation
- Complex values (maps, lists, structs): Use the Jsonpatch library to calculate minimal differences
Client-side patch application
On the client side, the Vue hook processes these diffs efficiently:Diff extraction
When the
updated() hook fires, it reads the data-props-diff attribute and parses the JSON array of patch operations.Patch application
The system applies each patch operation to the reactive props object using the JSON Patch implementation in
jsonPatch.ts.Reactivity triggering
Since the props object is reactive (created with Vue’s
reactive() function), any changes automatically trigger Vue’s reactivity system.Performance benefits
This diff-based approach provides several advantages:- Minimal network payload: Only changed data is transmitted
- Efficient client-side updates: Only changed reactive properties trigger re-renders
- Reduced memory pressure: Existing objects are patched rather than replaced
- Faster UI updates: Smaller changes mean less work for Vue’s virtual DOM
Example: When only a user’s email changes:
Disabling diffs for testing
Disabling diffs for testing
For testing scenarios or debugging purposes, diffing can be disabled globally via the
enable_props_diff: false configuration option, or per-component using the v-diff={false} attribute. When disabled, complete props are always sent instead of diffs.See Testing for details.Data flow
Props flow (server → client)
LiveView manages authoritative state and passes it to Vue components as props:- LiveView assigns are updated
- The HEEX template generates new prop data
- Only changed props are sent over WebSocket
- The Vue component automatically re-renders with new props
Event flow (client → server)
There are three main approaches for handling events: Standard Phoenix events (recommended for most cases):useLiveVue().pushEvent():
v-on: syntax:
liveSocket.execJS with the payload defined by the JS module:
Event handling best practices:
- Use
phx-clickfor simple, direct event handling - Use
live.pushEvent()when you need programmatic control or complex logic - Use
v-on:syntax when creating reusable Vue components that should be decoupled from specific LiveView implementations
SSR modes
LiveVue supports two different SSR implementations:NodeJS mode (production)
TheLiveVue.SSR.NodeJS module implements SSR by using a Node.js process pool:
- Uses the
nodejspackage to maintain a pool of Node.js processes - Calls the
renderfunction exposed byserver.mjs - Provides fast SSR with minimal overhead
- Requires Node.js 19+ in production
ViteJS mode (development)
TheLiveVue.SSR.ViteJS module implements SSR by making HTTP requests to Vite dev server:
- Sends POST requests to
http://{vite_host}/ssr_render - Uses the LiveVue Vite plugin to handle SSR
- Provides hot module replacement during development
- Simplifies the development workflow
SSR is intelligently applied only during initial page loads (dead renders), can be configured per component, and is skipped during live navigation for better performance.
Key design decisions
Hook-based integration
LiveVue uses Phoenix LiveView’s hook system rather than a separate JavaScript framework. This provides:- Seamless integration within LiveView’s lifecycle
- Automatic cleanup when elements are removed
- Natural compatibility with all Phoenix events
Reactive props and slots
Props and slots are made reactive using Vue’s reactivity system, enabling:- Efficient updates where only changed data triggers re-renders
- Full compatibility with Vue features like computed properties and watchers
- Minimal overhead for prop updates
Selective updates
LiveVue minimizes data transmission by:- Tracking only modified props, slots, and handlers
- Optimizing JSON encoding to prevent redundant work
- Phoenix updating only specific data attributes rather than re-rendering entire elements
Memory management
Automatic cleanup prevents memory leaks through proper hook lifecycle management:Slots implementation
Slots bridge HEEX templates and Vue components:- Rendered server-side as HTML
- Encoded as Base64 for safe transport
- Decoded on the client for integration into Vue’s slot system
Security considerations
Data sanitization
All data passed between server and client is properly sanitized:- Props are safely encoded with HTML escaping using
Jason.encode!(data, escape: :html_safe) - All user data is escaped before transmission
- Events go through Phoenix’s standard validation
Event security
Event handling maintains Phoenix’s security model:- All events are validated on the server
- Standard Phoenix CSRF protection applies
- LiveView’s authorization patterns work normally
Debugging and development
Development tools
LiveVue works with standard development tools:- Vue DevTools for full component inspection and debugging
- Phoenix LiveView Dashboard for server-side state monitoring
- Browser DevTools for network and WebSocket inspection
Debug features
Built-in debugging capabilities include:- Debug mode for detailed logging of component lifecycle
- Component resolution logs to help identify loading issues
- Event tracing to track events flowing between Vue and LiveView
Limitations and trade-offs
Current limitations
- Vue components can’t contain other Vue components
- Phoenix hooks don’t work inside slots
- Limited browser API access during server rendering
Design trade-offs
- The Vue runtime adds approximately 34KB gzipped to your application
- Additional abstraction layer between Phoenix and the client
- Requires understanding both Phoenix LiveView and Vue.js
When to use LiveVue
LiveVue is a good fit for:- Complex client-side interactions
- Rich UI components with local state
- Leveraging the Vue ecosystem (animations, charts, etc.)
- Teams with Vue.js expertise
- Simple forms and basic interactions
- Applications prioritizing minimal JavaScript
- Teams without Vue.js experience
Next steps
Configuration
Customize behavior and SSR settings
Basic usage
Practical patterns and examples
Client-side API
Vue composables and utilities
Testing
Test Vue components in LiveView