Getting Started
@humanspeak/svelte-virtual-chat is a high-performance virtual chat viewport for Svelte 5. It renders only visible messages to the DOM while handling follow-bottom behavior, LLM streaming stability, and history prepend with scroll anchor preservation.
Installation
pnpm add @humanspeak/svelte-virtual-chatpnpm add @humanspeak/svelte-virtual-chatnpm install @humanspeak/svelte-virtual-chatnpm install @humanspeak/svelte-virtual-chatQuick Start
Import the component and pass your messages array with a getMessageId function and a renderMessage snippet:
<script lang="ts">
import SvelteVirtualChat from '@humanspeak/svelte-virtual-chat'
type Message = { id: string; role: string; content: string }
let messages: Message[] = $state([
{ id: '1', role: 'assistant', content: 'Hello! How can I help?' },
{ id: '2', role: 'user', content: 'Tell me about Svelte.' }
])
</script>
<div class="h-[600px]">
<SvelteVirtualChat
{messages}
getMessageId={(msg) => msg.id}
estimatedMessageHeight={72}
containerClass="h-full"
viewportClass="h-full"
>
{#snippet renderMessage(message, index)}
<div class="p-4 border-b">
<strong>{message.role}</strong>
<p>{message.content}</p>
</div>
{/snippet}
</SvelteVirtualChat>
</div><script lang="ts">
import SvelteVirtualChat from '@humanspeak/svelte-virtual-chat'
type Message = { id: string; role: string; content: string }
let messages: Message[] = $state([
{ id: '1', role: 'assistant', content: 'Hello! How can I help?' },
{ id: '2', role: 'user', content: 'Tell me about Svelte.' }
])
</script>
<div class="h-[600px]">
<SvelteVirtualChat
{messages}
getMessageId={(msg) => msg.id}
estimatedMessageHeight={72}
containerClass="h-full"
viewportClass="h-full"
>
{#snippet renderMessage(message, index)}
<div class="p-4 border-b">
<strong>{message.role}</strong>
<p>{message.content}</p>
</div>
{/snippet}
</SvelteVirtualChat>
</div>Height Constraint
The component must have a defined height. The containerClass and viewportClass props control the outer and inner elements. The parent element needs a fixed or flex-derived height:
<!-- GOOD: parent has a defined height -->
<div class="h-screen flex flex-col">
<header>...</header>
<div class="flex-1 min-h-0">
<SvelteVirtualChat containerClass="h-full" viewportClass="h-full" ... />
</div>
</div><!-- GOOD: parent has a defined height -->
<div class="h-screen flex flex-col">
<header>...</header>
<div class="flex-1 min-h-0">
<SvelteVirtualChat containerClass="h-full" viewportClass="h-full" ... />
</div>
</div>Without a height constraint, the viewport expands to fit all content and virtualization won’t activate.
What’s Next
- Props Reference — all available props and their defaults
- Imperative API — scrollToBottom, scrollToMessage, getDebugInfo
- LLM Streaming Guide — pair with @humanspeak/svelte-markdown
- Interactive Examples — try it live