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

hugobarauna
This post announces the Livebook desktop app, a way to install Livebook on your machine without the requirement to have Elixir installed ...
New
fhunleth
We recently released Nerves 1.4.0 and an update to the Nerves new project generator, nerves_bootstrap. The biggest change is support for ...
New
jjcarstens
The Raspberry Pi is a very popular hardware platform for Nerves users and the official systems are getting an upgrade! :tada: :beers: Wh...
New
hwuethrich
Hi! I’m happy to share my first Elixir library. But first some … Background As an Elixir company from a country with 4 official languag...
New
zachdaniel
Ash 3.1 Released! Major themes Generators! These are just the first entries into a powerful new suite of tools. Check out the generator d...
New
sorentwo
Oban.Web is a view of Oban’s inner workings that you host directly within your Phoenix application. Powered by Oban Metrics and Phoenix L...
New
zachdaniel
Ash and AshPostgres generators/installers, built with igniter are available on main! I’ll be very grateful to anyone willing to give the...
New
bartblast
Hey! For those following Hologram’s progress… I’m excited to share that I’ve just published the official roadmap for Hologram. You can ch...
New
jjcarstens
Hey friends! :waving_hand: With NervesConf 2024 around the corner, Frank, myself, and the greater Nerves team wanted to share a survey w...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
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
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
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
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement