use-event-source
Reactive Server-Sent Events stream with typed, per-event decoding.
| Package | @vizejs/composable/use-event-source |
| Own the source | vize lib pull composable:use-event-source |
| Runtime exports | useEventSource |
| Gzip budget | 4608 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useEventSource } from "@vizejs/composable/use-event-source";
Try it
Follow server-sent events
Connect to a text/event-stream endpoint and show its connection state.
What to observe: Connect opens the stream; build lines arrive one per second until Build finished. Disconnect closes it.
The docs have no server, so host supplies a class that replays a build log; drop it in your app. Pass events and parse for named events, and autoReconnect to retry with backoff.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { useEventSource } from "@vizejs/composable/use-event-source";
// The docs have no server, so this class replays a build log. In your app, drop `host`
// and point the URL at an endpoint that streams `text/event-stream`.
class ReplayedBuildLog extends EventTarget {
readyState = 0;
constructor(_url: string) {
super();
queueMicrotask(() => {
this.readyState = 1;
this.dispatchEvent(new Event("open"));
});
["Compiling 42 files", "Type checking", "Build finished"].forEach((line, index) => {
setTimeout(
() => {
if (this.readyState === 1)
this.dispatchEvent(new MessageEvent("message", { data: line }));
},
(index + 1) * 1000,
);
});
}
close() {
this.readyState = 2;
}
}
const { status, data, open, close } = useEventSource("/api/build-events", {
host: ReplayedBuildLog,
immediate: false,
autoReconnect: false,
});
</script>
<template>
<div class="composable-example">
<p>Follow server-sent build events and show the connection state.</p>
<div class="example-actions">
<button type="button" :disabled="status !== 'closed'" @click="() => open()">Connect</button>
<button type="button" :disabled="status === 'closed'" @click="() => close()">
Disconnect
</button>
</div>
<output aria-live="polite">Status: {{ status }}{{ data ? ` · ${data}` : "" }}</output>
</div>
</template>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useEventSource |
networking | experimental | deterministic-fallback | caller-managed | caller, reactive-scope | web, server, worker, native, desktop, terminal | globalThis, window |
calculateRetryDelay, tryOnScopeDispose |
API
useEventSource
Reactive Server-Sent Events stream with typed, per-event decoding. Every subscribed event is decoded by its parser (raw text by default) and exposed as a discriminated message, plus data/event/lastEventId shortcuts and typed on() handlers. Transient drops use the browser's native reconnection; autoReconnect additionally reopens streams the browser closed for good. The stream and timers are released when the owning reactive scope stops (the caller owns close() outside a scope). Server rendering never connects and reports "closed".
function useEventSource<Events extends EventSourceEventMap = { message: string }>( url: MaybeRefOrGetter<string | URL | null | undefined>, ...[options]: unknown extends EventSourceParseRequirement<Events> ? [options?: UseEventSourceOptions<Events>] : [options: UseEventSourceOptions<Events> & EventSourceParseRequirement<Events>] ): EventSourceControls<Events>
const feed = useEventSource<{ price: number; notice: string }>("/stream", {
events: ["price", "notice"],
parse: { price: (raw) => Number(raw) },
});
feed.on("price", (price) => chart.push(price));
Types
EventSourceLike
Minimal EventSource instance used by useEventSource.
| Member | Type | Description |
|---|---|---|
readyState |
number |
0 connecting, 1 open, 2 closed (native values). |
close |
() => void |
Close the stream; the source never reconnects afterwards. |
addEventListener |
(type: string, listener: EventListener) => void |
Subscribe to open, error, or a named server event. |
removeEventListener |
(type: string, listener: EventListener) => void |
Remove a listener registered with addEventListener. |
EventSourceReconnectOptions
Options for reconnecting streams the browser gave up on.
| Member | Type | Description |
|---|---|---|
initialDelayMs? |
number |
Delay before the first retry, in milliseconds. |
multiplier? |
number |
Exponential multiplier applied for each subsequent retry. Values may be fractional but must be finite and at least one. The calculated delay is rounded up so a retry never starts earlier than the requested backoff. |
maximumDelayMs? |
number |
Inclusive ceiling for the calculated delay, in milliseconds. The ceiling may be lower than RetryDelayOptions.initialDelayMs; in that case it also caps the first retry. |
jitterRatio? |
number |
Fraction of the capped delay eligible for downward jitter. 0 is deterministic exponential backoff, 0.5 samples from the upper half of the range, and 1 applies full jitter from zero through the capped delay. Jitter never exceeds the unjittered delay. |
random? |
() => number |
Entropy source returning a number in the half-open interval [0, 1). It is called exactly once when the selected jitter range contains more than one integer millisecond, and is otherwise not read. |
retries? |
number |
Maximum consecutive reconnection attempts. |
onFailed? |
() => void |
Called once reconnection gives up. |
UseEventSourceOptions
Options for useEventSource.
| Member | Type | Description |
|---|---|---|
events? |
readonly (keyof Events & string)[] |
Named server events to subscribe to. |
parse? |
EventSourceParsers<Events> |
Per-event decoders (required for events whose data is not text). |
withCredentials? |
boolean |
Send cookies with cross-origin requests. |
host? |
MaybeRef<EventSourceConstructorLike | null | undefined> |
EventSource constructor (a plain value or ref, never a getter). Supplying one also enables automatic connection outside a browser. |
immediate? |
boolean |
Connect as soon as a URL is available (browser or explicit host only). |
autoReconnect? |
boolean | EventSourceReconnectOptions |
Reopen the stream with backoff after the browser closes it for good (native reconnection covers transient drops). |
scheduler? |
TimeoutScheduler |
Timer host for reconnection. |
onError? |
(failure: EventSourceFailure) => void |
Observe failures. |
EventSourceControls
Reactive state and controls returned by useEventSource.
| Member | Type | Description |
|---|---|---|
status |
Readonly<Ref<EventSourceStatus>> |
Connection status. |
message |
Readonly<ShallowRef<EventSourceMessage<Events> | undefined>> |
Latest decoded event, discriminated by name. |
data |
Readonly<ShallowRef<Events[keyof Events & string] | undefined>> |
Data of the latest event. |
event |
Readonly<Ref<(keyof Events & string) | undefined>> |
Name of the latest event. |
lastEventId |
Readonly<Ref<string | undefined>> |
id: field of the latest event. |
error |
Readonly<ShallowRef<EventSourceFailure | undefined>> |
Latest failure, cleared when the stream opens. |
source |
Readonly<ShallowRef<EventSourceLike | undefined>> |
Current underlying source, if any. |
on |
<Name extends keyof Events & string>( event: Name, handler: (data: NoInfer<Events[Name]>, lastEventId: string) => void, ) => () => void |
Observe one subscribed event with typed data. |
open |
() => void |
Open (or reopen) the stream. |
close |
() => void |
Close the stream and disable reconnection. |