SvelteVirtualChat Component
The SvelteVirtualChat component is a message-aware virtual viewport for chat UIs. It uses normal top-to-bottom chronological order internally — no inverted geometry.
<script>
import SvelteVirtualChat from '@humanspeak/svelte-virtual-chat'
</script>
<SvelteVirtualChat
{messages}
getMessageId={(msg) => msg.id}
containerClass="h-full"
viewportClass="h-full"
>
{#snippet renderMessage(message, index)}
<div class="p-4">{message.content}</div>
{/snippet}
</SvelteVirtualChat><script>
import SvelteVirtualChat from '@humanspeak/svelte-virtual-chat'
</script>
<SvelteVirtualChat
{messages}
getMessageId={(msg) => msg.id}
containerClass="h-full"
viewportClass="h-full"
>
{#snippet renderMessage(message, index)}
<div class="p-4">{message.content}</div>
{/snippet}
</SvelteVirtualChat>How It Works
- Height caching — each message’s height is measured via ResizeObserver and cached by ID
- Visible range — on every scroll, the component calculates which messages fall within the viewport plus overscan
- Absolute positioning — only visible messages are rendered, positioned via
transform: translateY() - Follow-bottom — when at bottom, new messages and height changes trigger an automatic snap
- Bottom gravity — when messages don’t fill the viewport, they sit at the bottom (like a real chat)
Generic Type Parameter
The component is generic over your message type. TypeScript infers TMessage from the messages prop automatically:
<script lang="ts">
import SvelteVirtualChat from '@humanspeak/svelte-virtual-chat'
type MyMessage = { id: string; role: string; content: string }
let messages: MyMessage[] = $state([...])
</script>
<!-- TMessage is inferred as MyMessage from the messages prop -->
<SvelteVirtualChat
{messages}
getMessageId={(msg) => msg.id}
...
/><script lang="ts">
import SvelteVirtualChat from '@humanspeak/svelte-virtual-chat'
type MyMessage = { id: string; role: string; content: string }
let messages: MyMessage[] = $state([...])
</script>
<!-- TMessage is inferred as MyMessage from the messages prop -->
<SvelteVirtualChat
{messages}
getMessageId={(msg) => msg.id}
...
/>No explicit generic annotation is needed — the type flows from your messages array.
Related
- Props Reference — complete props table
- Imperative API — exported methods
- Getting Started — installation and setup