logo

Svelte Virtual Chat

A high-performance virtual chat viewport for Svelte 5.
Purpose-built for LLM conversations, support chat, and any message-based UI.

  • Svelte 5
  • TypeScript
  • Follow-Bottom
  • LLM Streaming
  • Zero Deps

Watch It Stream in Real-Time

This is a live SvelteVirtualChat component. Messages stream token-by-token while the viewport stays pinned to bottom — no jitter.

Live chat demo
Full Demo

Built for chat, not lists

Every feature is a direct response to a real problem in chat UI development.

Follow-Bottom

Viewport stays pinned to the newest message. Scroll away and it stops. Return and it resumes.

LLM Streaming

Height changes from token streaming are batched per frame. No jitter, no jumps, no workarounds.

Virtualized

Only visible messages exist in the DOM. 10,000 messages renders ~20 DOM nodes.

History Prepend

Load older messages at the top. Scroll anchor preservation keeps the user's position stable.

Message-Aware

Uses message IDs for identity. Height caching, scroll-to-message, and keyed rendering built in.

Svelte 5 + TypeScript

Full generics, runes ($state, $derived, $effect), and snippets. Zero dependencies.

Drop-in component

One component, one snippet, done. Pair with @humanspeak/svelte-markdown for rich LLM output.

+page.svelte
<script lang="ts">
  import SvelteVirtualChat from '@humanspeak/svelte-virtual-chat'
  let messages = $state([...])
</script>

<SvelteVirtualChat
  {messages}
  getMessageId={(msg) => msg.id}
  estimatedMessageHeight={72}
  containerClass="h-[600px]"
  viewportClass="h-full"
>
  {#snippet renderMessage(message, index)}
    <div class="p-4">{message.content}</div>
  {/snippet}
</SvelteVirtualChat>
Install
pnpm add @humanspeak/svelte-virtual-chat