svelte-socket Svelte Themes

Svelte Socket

A socket provider for Svelte Kit

svelte-socket

WebSocket wrapper for Svelte 5 using runes.

Overview

This library provides:

  • SvelteSocket - WebSocket wrapper class with reactive state properties (connectionStatus, sentMessages, receivedMessages)
  • SocketProvider - Context provider component that instantiates SvelteSocket and makes it available to child components
  • Debugger - UI panel component showing connection status, sent messages, and received messages
  • useSocket() - Hook to access socket instance from context

Features

  • Constructor accepts configuration object with URL and optional callbacks (onMessage, onOpen, onClose, onError)
  • Optional debug logging via debug flag
  • Auto-reconnection with configurable delay and max attempts
  • Reactive message history (sent and received)
  • All state properties use Svelte 5 $state runes
  • TypeScript support

Installation

npm install svelte-socket

Usage

In parent components including +page.svelte or +layout.svelte...

<script>
    import { SvelteSocket } from 'svelte-socket';

    // Callbacks can be added on construction...
    const socket = new SvelteSocket({
        url: 'ws://localhost:8080',
        onOpen: () => console.log('Hello, server!')
    });
    const isConnected = $derived(socket.connectionStatus === WebSocket.OPEN);

    // ...or later using addEventListener
    socket.addEventListener('message', (event) => {
        console.log(event.data);
    });

    socket.sendMessage('text');
</script>

<SocketProvider {svelteSocket}>
    {@render children()}
</SocketProvider>

In any child component...

<script>
    import { useSocket } from 'svelte-socket';
    let { children } = $props();
    const socket = useSocket()
    let isConnected = $derived(socket.connectionStatus === WebSocket.OPEN);
    let receivedMessages = $derived(socket.receivedMessages)
</script>

<p>{isConnected}</p>
{#each receivedMessages as msg, i}
    <p>{msg.origin}<p>
{/each}

API

SvelteSocket

Constructor

new SvelteSocket(options: SocketConstructorArgs)

Options:

Property Type Required Description
url string Yes WebSocket server URL
onMessage (event: MessageEvent) => void No Called when message received
onOpen (event: Event) => void No Called when connection opens
onClose (event: CloseEvent) => void No Called when connection closes
onError (event: Event) => void No Called on error
debug boolean No Enable console logging (default: false)
reconnectOptions ReconnectOptions No Auto-reconnection config
maxMessageHistory number No Max messages to keep in history (default: 50). Set to 0 for unlimited

ReconnectOptions:

Property Type Description
enabled boolean Enable auto-reconnection
delay number Milliseconds before reconnect attempt
maxAttempts number Maximum reconnection attempts

Example:

const socket = new SvelteSocket({
    url: 'ws://localhost:8080',
    debug: true,
    maxMessageHistory: 100, // Keep last 100 messages (default: 50)
    reconnectOptions: {
        enabled: true,
        delay: 1000,
        maxAttempts: 5
    },
    onMessage: (event) => console.log(event.data),
    onOpen: () => console.log('connected'),
    onClose: () => console.log('disconnected')
});

Properties

Property Type Description
connectionStatus WebSocket['readyState'] Connection state: 0 (CONNECTING), 1 (OPEN), 2 (CLOSING), 3 (CLOSED)
sentMessages Array<{message: string | ArrayBuffer | Blob | ArrayBufferView, timestamp: number}> Sent message history (newest first, via unshift). Auto-trimmed to maxMessageHistory
receivedMessages Array<{message: MessageEvent}> Received message history (newest first, via unshift). Auto-trimmed to maxMessageHistory
maxMessageHistory number Maximum number of messages to keep in history (default: 50, readonly)

Example:

<script>
    const socket = new SvelteSocket({ url: 'ws://localhost:8080' });

    const connectionStatus = $derived(socket.connectionStatus);
    const sentMessages = $derived(socket.sentMessages);
    const receivedMessages = $derived(socket.receivedMessages);
</script>

{#if connectionStatus === WebSocket.OPEN}
    <p>Open</p>
{:else if connectionStatus === WebSocket.CONNECTING}
    <p>Connecting</p>
{:else}
    <p>Closed</p>
{/if}

<p>{sentMessages.length} sent</p>
<p>{receivedMessages.length} received</p>

{#each receivedMessages as { message }}
    <div>{message.data}</div>
{/each}

Methods

addEventListener(event, callback)
addEventListener(
    event: 'message' | 'close' | 'open' | 'error',
    callback: (event: MessageEvent | CloseEvent | Event) => void
): void

Adds event listener to WebSocket. The callback type is automatically inferred based on the event type:

  • 'message'(event: MessageEvent) => void
  • 'close'(event: CloseEvent) => void
  • 'open'(event: Event) => void
  • 'error'(event: Event) => void

Throws if socket not connected.

socket.addEventListener('message', (event) => {
    console.log(event.data); // event is typed as MessageEvent
});
removeEventListener(event, callback)
removeEventListener(
    event: 'message' | 'close' | 'open' | 'error',
    callback: (event: MessageEvent | CloseEvent | Event) => void
): void

Removes event listener. Callback types match addEventListener.

const handler = (event) => console.log(event.data);
socket.addEventListener('message', handler);
socket.removeEventListener('message', handler);
sendMessage(message)
sendMessage(message: string | ArrayBuffer | Blob | ArrayBufferView): void

Sends a text or binary message through the WebSocket. Supports strings, ArrayBuffer, Blob, TypedArray, and DataView. Stores in sentMessages array. Throws if not connected or not in OPEN state.

Example:

// Send text
socket.sendMessage('Hello, server!');
socket.sendMessage(JSON.stringify({ type: 'ping' }));

// Send binary data
const buffer = new Uint8Array([1, 2, 3, 4]);
socket.sendMessage(buffer);
clearSentMessages()
clearSentMessages(): void

Clears sentMessages array.

socket.clearSentMessages();
clearReceivedMessages()
clearReceivedMessages(): void

Clears receivedMessages array.

socket.clearReceivedMessages();
removeSocket()
removeSocket(): void

Closes WebSocket connection. Clears message history. Prevents reconnection.

socket.removeSocket();

SocketProvider

Context provider component that makes a socket instance available to child components.

Props:

Property Type Required Description
url string Yes* WebSocket server URL (automatically creates socket)
svelteSocket SvelteSocket Yes* Pre-configured SvelteSocket instance
children Snippet No Child components

*At least one of url or svelteSocket must be provided. If both are provided, svelteSocket takes precedence.

Basic Usage:

The simplest way to use the provider is to pass a url, which automatically creates a SvelteSocket for you:

<script>
    import { SocketProvider } from 'svelte-socket';

    let { children } = $props();
</script>

<SocketProvider url="ws://localhost:8080">
    {@render children()}
</SocketProvider>

Custom Socket Configuration:

You can also create your own SvelteSocket with custom callbacks and options, then pass it to the provider:

<script>
    import { SocketProvider, SvelteSocket } from 'svelte-socket';

    let { children } = $props();

    const svelteSocket = new SvelteSocket({
        url: 'ws://localhost:8080',
        debug: true,
        reconnectOptions: {
            enabled: true,
            delay: 1000,
            maxAttempts: 5
        },
        onMessage: (event) => {
            console.log('Received:', event.data);
        },
        onOpen: () => {
            console.log('Connected!');
        }
    });
</script>

<SocketProvider {svelteSocket}>
    {@render children()}
</SocketProvider>

useSocket()

useSocket(): SvelteSocket

Returns socket instance from context.

Throws if not used within SocketProvider.

Example:

<script>
    import { useSocket } from 'svelte-socket';

    const socket = useSocket();
</script>

Debugger

Debug UI component. Shows connection status, sent messages, received messages.

Props:

Property Type Required
socket SvelteSocket Yes

Example:

<script>
    import { SvelteSocket, Debugger } from 'svelte-socket';

    const socket = new SvelteSocket({ url: 'ws://localhost:8080' });
</script>

<Debugger {socket} />

Displays:

  • Connection state (CONNECTING/OPEN/CLOSING/CLOSED)
  • Message counts (sent/received)
  • Sent message history with timestamps
  • Received message history with data

Styling Requirements:

This component requires Tailwind CSS. You must configure Tailwind to scan the package files:

Tailwind v4:

/* app.css */
@import 'tailwindcss';
@source '../node_modules/@hardingjam/svelte-socket/dist/**/*.svelte';

Tailwind v3:

// tailwind.config.js
export default {
    content: [
        './src/**/*.{html,js,svelte,ts}',
        './node_modules/@hardingjam/svelte-socket/dist/**/*.svelte'
    ]
    // ... rest of config
};

Context Functions

setSocket(socket)

setSocket(socket: SvelteSocket): void

Sets socket in Svelte context. Used by SocketProvider.

getSocketContext()

getSocketContext(): SvelteSocket

Gets socket from context. Throws if not found.

Examples

Basic

<script>
    import { SvelteSocket } from 'svelte-socket';

    const socket = new SvelteSocket({ url: 'ws://localhost:8080' });

    socket.addEventListener('message', (event) => {
        console.log(event.data);
    });

    function send() {
        socket.sendMessage('test');
    }
</script>

<button onclick={send}>Send</button>

Auto-reconnect

<script>
    import { SvelteSocket } from 'svelte-socket';

    const socket = new SvelteSocket({
        url: 'ws://localhost:8080',
        debug: true,
        reconnectOptions: {
            enabled: true,
            delay: 1000,
            maxAttempts: 5
        }
    });
</script>

JSON Messages

<script>
    import { SvelteSocket } from 'svelte-socket';

    const socket = new SvelteSocket({ url: 'ws://localhost:8080' });

    socket.addEventListener('message', (event) => {
        const data = JSON.parse(event.data);

        if (data.type === 'ping') {
            socket.sendMessage(JSON.stringify({ type: 'pong' }));
        }
    });
</script>

Message History

<script>
    import { SvelteSocket } from 'svelte-socket';

    const socket = new SvelteSocket({ url: 'ws://localhost:8080' });
    const sentMessages = $derived(socket.sentMessages);
    const receivedMessages = $derived(socket.receivedMessages);

    let input = $state('');

    function send() {
        if (input) {
            socket.sendMessage(input);
            input = '';
        }
    }
</script>

<input bind:value={input} />
<button onclick={send}>Send</button>

<h3>Sent ({sentMessages.length})</h3>
{#each sentMessages as { message, timestamp }}
    <div>
        {new Date(timestamp).toLocaleTimeString()}: {message}
    </div>
{/each}

<h3>Received ({receivedMessages.length})</h3>
{#each receivedMessages as { message }}
    <div>{message.data}</div>
{/each}

<button onclick={() => socket.clearSentMessages()}>Clear</button>

With Provider

<!-- +layout.svelte -->
<script>
    import { SocketProvider } from 'svelte-socket';

    let { children } = $props();
</script>

<SocketProvider url="ws://localhost:8080">
    {@render children()}
</SocketProvider>

<!-- +page.svelte -->
<script>
    import { useSocket } from 'svelte-socket';

    const socket = useSocket();

    socket.addEventListener('message', (event) => {
        console.log(event.data);
    });
</script>

TouchDesigner Integration

Broadcast to all connected clients:

# TouchDesigner Text DAT
def broadcast():
    webServer = op('webserver1')
    clients = webServer.clients

    for client in clients:
        webServer.webSocketSendText(client, "message")

    print(f"Sent to {len(clients)} clients")

Requirements

  • Svelte 5.0+
  • WebSocket support

License

MIT

Top categories

Loading Svelte Themes