Jskalc

Jskalc

LiveVue - v1.0 released with igniter installer, forms support and more!

LiveVue v1.0 released

After four release candidates and a lot of community feedback, LiveVue 1.0 is stable :tada:

I’ve built a dedicated website with interactive examples: livevue.skalecki.dev

And wrote the full story behind the library: The Story of LiveVue

What Changed

New Composables

useLiveForm — Server-side validation with Ecto changesets, nested objects, dynamic arrays. Fully typed:

<script setup lang="ts">
import { useLiveForm, type Form } from 'live_vue'

type UserForm = {
  name: string
  profile: { bio: string; skills: string[] }
}

const props = defineProps<{ form: Form<UserForm> }>()

const form = useLiveForm(() => props.form, {
  changeEvent: 'validate',
  submitEvent: 'submit'
})

// Type-safe field access — typos caught at compile time
const nameField = form.field('name')
const bioField = form.field('profile.bio')
const skillsArray = form.fieldArray('profile.skills')
</script>

<template>
  <input v-bind="nameField.inputAttrs.value" />
  <span v-if="nameField.errorMessage.value">{{ nameField.errorMessage.value }}</span>

  <div v-for="(skill, i) in skillsArray.fields.value" :key="i">
    <input v-bind="skill.inputAttrs.value" />
    <button @click="skillsArray.remove(i)">Remove</button>
  </div>
  <button @click="skillsArray.add('')">Add Skill</button>

  <button @click="form.submit()" :disabled="!form.isValid.value">Submit</button>
</template>

LiveView side stays exactly as you’d expect:

def handle_event("validate", %{"user" => params}, socket) do
  changeset = User.changeset(%User{}, params) |> Map.put(:action, :validate)
  {:noreply, assign(socket, form: to_form(changeset, as: :user))}
end

useLiveUpload — File uploads with progress tracking and drag-and-drop:

<script setup>
import { useLiveUpload } from 'live_vue'

const { entries, showFilePicker, addFiles, progress } = useLiveUpload(
  () => props.upload,
  { submitEvent: 'save' }
)
</script>

<template>
  <div @drop.prevent="e => addFiles(e.dataTransfer.files)" @dragover.prevent>
    Drop files or <button @click="showFilePicker">browse</button>
    <div v-for="entry in entries" :key="entry.ref">
      {{ entry.client_name }} — {{ entry.progress }}%
    </div>
  </div>
</template>

useLiveConnection — Reactive WebSocket status for offline indicators:

<script setup>
import { useLiveConnection } from 'live_vue'
const { isConnected, connectionState } = useLiveConnection()
</script>

<template>
  <div :class="isConnected ? 'text-green-500' : 'text-red-500'">
    {{ connectionState }}
  </div>
</template>

useEventReply — Bi-directional events with server responses:

<script setup>
import { useEventReply } from 'live_vue'

const { data, isLoading, execute } = useEventReply('fetch_user')
</script>

<template>
  <button @click="execute({ id: 123 })" :disabled="isLoading">
    {{ isLoading ? 'Loading...' : 'Fetch User' }}
  </button>
  <div v-if="data">{{ data.name }}</div>
</template>

Performance: JSON Patch Diffs

Props now use RFC 6902 JSON Patch. Only differences are sent:

[{"op": "replace", "path": "/users/1/name", "value": "Robert"}]

Inserting at the beginning of a 100-item list? One operation, not 100 — thanks to ID-based matching.

Phoenix Streams

Streams work transparently as reactive arrays:

<.vue messages={@streams.messages} v-component="Chat" v-socket={@socket} />
<script setup>
// messages is a reactive array — streams handled automatically
const props = defineProps<{ messages: Message[] }>()
</script>

Developer Experience

  • One-command install: mix igniter.install live_vue
  • No JS build step — TypeScript source exported directly, Vite handles it
  • VS Code extension for ~VUE sigil syntax highlighting

Breaking Changes

  • shared_props removed — pass props explicitly
  • nillify_not_loadednilify_not_loaded (typo fix)

Links

Discuss and upvote also on Hacker News.

Happy New Year!

Most Liked

mikehostetler

mikehostetler

Great work! I’ve been mostly a React guy, but I haven’t been able to find a good flow when using React with LiveView, so this may convert me!

Jskalc

Jskalc

I would like to eventually port that work to LiveReact / LiveSvelte, since most of it should be easily transferrable. But for now I have to focus on other priorities :smiley:

sezaru

sezaru

Does useLiveForm also works with Ash.Changeset forms?

I’m considering using LiveVue in a new project but that project will use Ash instead of Ecto directly.

Normally, when creating a form in LV for Ash, you will use AshPhoenix.Form — ash_phoenix v2.3.23 which will wrap around Phoenix forms, not sure if it can be used with LiveVue too.

Where Next?

Popular in News & Updates Top

mobileoverlord
New versions of the Kiosk systems are out. These systems update official Nerves systems with a local web browser for rendering user inter...
New
fhunleth
I wanted to let everyone know that the Erlang Ecosystem Foundation (EEF) has a working group dedicated to embedded systems and IoT. We ha...
New
DominikWolek
Hey everyone! The Membrane Framework has a new website! It contains tutorials, blog posts, and other resources you’ll find handy while u...
New
jjcarstens
Testing code destined for hardware can be tricky, but it just got one tiny bit easier! :tty0tty was just released which is an Elixir por...
New
zachdaniel
The second video from the Ash Primers series is out! https://www.youtube.com/watch?v=GtsL_lIis4Q This one is about the migration generato...
New
DominikWolek
We are launching a cloud-based video streaming platform, which will allow you to use Membrane without all the hassle of maintaining your ...
New
mickel8
Hello everyone! :wave: I am thrilled to announce a new version of Jellyfish Media Server - v0.2.0! :tada: Features: Added RTSP compon...
New
zachdaniel
Join us for our first Ash Office Hours next Thursday at 6PM EST! Myself and anyone from the core team who can make it will be answering q...
New
zachdaniel
Hey everyone! What I’ll cover in this post: Major refactors The future of Ash.Flow Current state of atomics and bulk actions Whats nex...
New
mat-hek
Hi everyone, I’d like to share with you a new library from the Membrane team - Boombox. It’s a simple streaming tool built on top of Mem...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement