Carets
vue-stream-markdown includes built-in caret (cursor) indicators that display at the end of streaming content. Carets provide a visual cue to users that content is actively being generated, similar to a blinking cursor in a text editor.
Overview
The caret prop adds a visual indicator at the end of your streaming markdown content. This feature enhances the user experience by making it clear when content is actively being generated versus when generation is complete.
Key features:
- Two built-in styles - Choose between block (
▋) and circle (●) carets - Automatic positioning - Carets automatically appear at the last text node that is still loading
- Streaming-aware - Only displays when
mode="streaming"(default) andcaretprop is set - Efficient rendering - Uses inline span elements for optimal performance
Usage
To enable carets, pass the caret prop with either "block" or "circle":
<script setup lang="ts">
import { ref } from 'vue'
import { Markdown } from 'vue-stream-markdown'
const content = ref('')
</script>
<template>
<Markdown caret="block">
{{ content }}
</Markdown>
</template>Caret Styles
vue-stream-markdown provides two built-in caret styles:
Block Caret
The block caret displays a vertical bar (▋) similar to a terminal cursor:
<template>
<Markdown caret="block">
Streaming content...
</Markdown>
</template>Streaming content with block caret
This is a paragraph that continues streaming.
Circle Caret
The circle caret displays a filled circle (●) for a subtler indicator:
<template>
<Markdown caret="circle">
Streaming content...
</Markdown>
</template>Streaming content with circle caret
This is a paragraph that continues streaming.
Behavior
The caret visibility is controlled by two conditions:
caretprop is set - You must specify either"block"or"circle"mode="streaming"(default) - Carets only work in streaming mode
The caret automatically appears on the last text node that is still in a loading state. When the content finishes streaming and all nodes are fully parsed, the caret disappears:
Streaming content is now complete .
The caret has disappeared.
Conditional Display
vue-stream-markdown doesn't know about roles or message ordering, so you should conditionally show carets for specific messages, such as only displaying them for the last message in a chat and only displaying them from assistant messages:
<template>
<Markdown
v-for="(message, index) in messages"
:key="message.id"
:caret="isAssistant(message) && isLatest(index)
? 'block'
: undefined"
:mode="isAssistant(message) && isLatest(index) && isStreaming
? 'streaming'
: 'static'"
>
{{ message.content }}
</Markdown>
</template>Technical Details
Carets are implemented using inline span elements:
- The caret is rendered as a
<span>element withdata-stream-markdown="caret"attribute - The span is appended to the last text node that has
loading: true - The caret character is displayed inline within the span
- When text node loading completes or
caretprop isundefined, the span is removed from the DOM
This approach ensures the caret always appears at the correct position within the text content.