LiveVue 1.0
Examples Server Events

Server Events

Server-to-client communication using push_event/3 on the server and useLiveEvent() on the client for real-time notifications and updates.

What this example shows

1
push_event
Server sends to client
2
useLiveEvent()
Client receives events
3
Multiple Events
Different event types
ServerEvents.vue
<script setup lang="ts">
import { ref } from "vue"
import { useLiveVue, useLiveEvent } from "live_vue"

type Notification = {
  id: number
  type: string
  message: string
  timestamp: number
}

type Alert = {
  id: number
  message: string
  timestamp: number
}

const props = defineProps<{ notificationCount: number }>()

const notifications = ref<Notification[]>([])
const alerts = ref<Alert[]>([])
const live = useLiveVue()

useLiveEvent("notification", (data: Notification) => {
  notifications.value = [data, ...notifications.value].slice(0, 5)
})

useLiveEvent("alert", (data: Alert) => {
  alerts.value = [data, ...alerts.value].slice(0, 3)
})

function triggerNotification(type: string) {
  live.pushEvent("trigger_notification", { type })
}

function triggerAlert(message: string) {
  live.pushEvent("trigger_alert", { message })
}

function getNotificationColor(type: string) {
  const colors: Record<string, string> = {
    info: "badge-info",
    success: "badge-success",
    warning: "badge-warning",
    error: "badge-error"
  }
  return colors[type] || colors.info
}
</script>

<template>
  <div class="card bg-base-200 p-6 space-y-6">
    <div class="space-y-3">
      <div class="text-sm font-medium text-neutral">Trigger server notifications</div>
      <div class="flex gap-2 flex-wrap">
        <button @click="triggerNotification('info')" class="btn btn-info btn-sm">
          Info
        </button>
        <button @click="triggerNotification('success')" class="btn btn-success btn-sm">
          Success
        </button>
        <button @click="triggerNotification('warning')" class="btn btn-warning btn-sm">
          Warning
        </button>
        <button @click="triggerNotification('error')" class="btn btn-error btn-sm">
          Error
        </button>
      </div>
    </div>

    <div class="space-y-3">
      <div class="text-sm font-medium text-neutral">Trigger server alerts</div>
      <div class="flex gap-2 flex-wrap">
        <button @click="triggerAlert('Your session will expire soon')" class="btn btn-outline btn-sm">
          Session Alert
        </button>
        <button @click="triggerAlert('New message received')" class="btn btn-outline btn-sm">
          Message Alert
        </button>
      </div>
    </div>

    <div class="grid grid-cols-2 gap-4 max-sm:grid-cols-1">
      <div class="space-y-3">
        <div class="flex items-center justify-between">
          <div class="text-sm font-medium text-neutral">Notifications</div>
          <div class="text-xs text-neutral/50">{{ props.notificationCount }} total</div>
        </div>
        <div class="min-h-[200px] p-4 rounded-lg bg-base-100 border border-base-300">
          <div v-if="notifications.length === 0" class="text-neutral/50 text-sm text-center py-8">
            No notifications yet
          </div>
          <div v-else class="space-y-2">
            <div
              v-for="notif in notifications"
              :key="notif.id"
              :class="['badge p-3 h-auto w-full justify-start text-sm', getNotificationColor(notif.type)]"
            >
              <div class="flex items-start justify-between gap-2 w-full">
                <div class="flex-1">
                  <div class="font-medium capitalize mb-1">{{ notif.type }}</div>
                  <div class="text-xs opacity-80">{{ notif.message }}</div>
                </div>
                <div class="text-xs opacity-50 shrink-0">
                  {{ new Date(notif.timestamp * 1000).toLocaleTimeString() }}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="space-y-3">
        <div class="flex items-center justify-between">
          <div class="text-sm font-medium text-neutral">Alerts</div>
          <div class="text-xs text-neutral/50">Recent 3</div>
        </div>
        <div class="min-h-[200px] p-4 rounded-lg bg-base-100 border border-base-300">
          <div v-if="alerts.length === 0" class="text-neutral/50 text-sm text-center py-8">
            No alerts yet
          </div>
          <div v-else class="space-y-2">
            <div v-for="alert in alerts" :key="alert.id" class="p-3 rounded-lg border border-base-300 bg-base-300 text-sm">
              <div class="flex items-start justify-between gap-2">
                <div class="flex-1">{{ alert.message }}</div>
                <div class="text-xs text-neutral/50 shrink-0">
                  {{ new Date(alert.timestamp * 1000).toLocaleTimeString() }}
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

How it works

1 Server pushes events to client

Use push_event/3 in LiveView to send data to the client. The first argument is the socket, the second is the event name, and the third is the payload.

push_event(socket, "notification", %{message: "Hello!"})

2 useLiveEvent() listens for events

The useLiveEvent() composable registers a listener for server events. It automatically handles cleanup when the component unmounts.

useLiveEvent('notification', (data) => { /* handle event */ })

3 Multiple event types

You can use different event names for different types of server pushes. Each useLiveEvent() call can listen to a specific event type.

useLiveEvent('notification', handleNotification)
useLiveEvent('alert', handleAlert)

4 Triggered by any handle_event

Server events can be pushed from any handle_event/3 callback. This example triggers them from button clicks, but they could come from background processes, PubSub, or any other source.

def handle_event("trigger", _, socket) do
  {:noreply, push_event(socket, "event_name", data)}
end
Next up: Navigation with Link component
Navigation →