Skip to main content
The main component for rendering AI-generated content. Automatically detects and renders artifacts including code blocks, forms, social previews, images, videos, and more.

Import

import { ArtifactuseAgentMessage } from 'artifactuse/vue'

Usage

<template>
  <ArtifactuseAgentMessage 
    :content="message.content"
    :message-id="message.id"
    :typing="isStreaming"
    :is-last-message="isLastMessage"
    @artifact-detected="onDetected"
    @artifact-open="onOpen"
    @form-submit="onFormSubmit"
    @form-cancel="onFormCancel"
    @form-button-click="onFormButtonClick"
    @social-copy="onSocialCopy"
    @media-open="onMediaOpen"
  />
</template>

Props

PropTypeDefaultDescription
contentstringRequiredRaw message content from AI (Markdown, code blocks, JSON artifacts)
messageIdstringRequiredUnique identifier for the message
typingbooleanfalseShow typing indicator (use while streaming)
inlineCardsbooleantrueShow clickable cards for panel artifacts inline. Also configurable globally.
isLastMessagebooleanfalseWhether this is the last message in the conversation. Keeps forms active after page reload.
inlinePreviewobjectnullOverride global inlinePreview config for this message
inlineCodeobjectnullOverride global inlineCode config for this message
tabsstring[]nullOverride visible panel tabs for artifacts from this message
viewModestringnullOverride initial panel view mode for artifacts from this message

Events

EventPayloadDescription
artifact-detectedArtifact[]Fired when artifacts are detected in content
artifact-openArtifactFired when user clicks an artifact card to open panel
form-submit{ formId, action, values, timestamp }Fired when an inline form is submitted
form-cancel{ formId, action, buttonName, timestamp }Fired when an inline form is cancelled
form-button-click{ formId, action, buttonName, buttonLabel, values, timestamp }Fired when a custom button is clicked
social-copy{ platform, text }Fired when social preview text is copied
media-open{ type, src, alt, caption }Fired when image/PDF is opened in lightbox viewer
Event names use kebab-case in Vue (@form-submit) and camelCase in React (onFormSubmit). Svelte uses kebab-case with on: prefix (on:form-submit).

Artifact Rendering

The component automatically renders different artifact types:
Artifact TypeRendering
code (HTML, React, Vue, etc.)Clickable card → Opens in Panel
form with display: "inline"Inline form directly in message
form with display: "panel"Clickable card → Opens in Panel
socialInline social media preview
ImagesInline with lightbox on click
VideosInline embed (YouTube, Vimeo, etc.)
Other embedsInline (maps, documents, etc.)

Inline Code Preview

By default, code artifacts render as clickable cards. Enable inlinePreview in your SDK config to show truncated syntax-highlighted code previews directly in the message:
// Global config
provideArtifactuse({
  inlinePreview: {
    maxLines: 15,
    languages: ['smartdiff', 'html', 'javascript', 'jsx'],
  },
})
<!-- Or per-message override -->
<ArtifactuseAgentMessage
  :content="msg.content"
  :message-id="msg.id"
  :inline-preview="{ maxLines: 10, languages: ['html'] }"
/>
OptionTypeDefaultDescription
maxLinesnumber15Max lines to show before truncation
languagesstring[] or true[]Languages to show inline preview for, or true for all
excludeLanguagesstring[][]Languages to exclude from inline preview (used with languages: true)
minClickableLinesnumber or objectnullDisable clicking for short code blocks. Number shorthand or { lines, ignoreLanguages }
actionLabelstring or objectnullCustomize the fade overlay label. String shorthand or { langKey: label, default: label }
Clicking a truncated preview opens the full artifact in the panel. Languages not listed still render as cards.
Inline code preview requires Prism.js for syntax highlighting. Load Prism and language grammars via CDN or npm.

Exclude Languages

When using languages: true, exclude specific languages from inline preview with excludeLanguages. Excluded languages fall back to artifact cards:
provideArtifactuse({
  inlinePreview: {
    languages: true,
    excludeLanguages: ['typescript', 'go', 'rust'],
  },
})
This is only meaningful when languages: true. When languages is an array, simply omit the language from the array instead.

Non-Clickable Short Code

When code is shorter than maxLines, the full code is visible — clicking opens a panel that shows the same content. Use minClickableLines to disable clicking for these short blocks:
provideArtifactuse({
  inlinePreview: {
    maxLines: 15,
    languages: ['html', 'javascript', 'python'],
    minClickableLines: 10,  // short code (< 10 lines) is non-clickable
  },
})
For languages where the panel adds value (e.g., HTML renders a live preview), use ignoreLanguages to keep them clickable:
minClickableLines: {
  lines: 10,
  ignoreLanguages: ['html', 'markdown', 'jsx', 'vue'],
},

Custom Action Labels

Customize the fade overlay label text per language:
provideArtifactuse({
  inlinePreview: {
    maxLines: 15,
    languages: ['html', 'javascript', 'markdown'],
    actionLabel: {
      html: 'Open preview',
      markdown: 'Open document',
      default: 'View full code',  // fallback for unlisted languages
    },
  },
})
String shorthand applies to all languages:
actionLabel: 'Click to expand',
The (N lines) suffix is always appended automatically (e.g., “Open preview (24 lines)”).

Inline Code

To show full syntax-highlighted code directly in the message without extraction or panel, enable inlineCode:
// Global config
provideArtifactuse({
  inlineCode: {
    languages: ['css', 'bash', 'sql'],  // or true for all
  },
})
<!-- Or per-message override -->
<ArtifactuseAgentMessage
  :content="msg.content"
  :message-id="msg.id"
  :inline-code="{ languages: true }"
/>
OptionTypeDefaultDescription
languagesstring[] or true[]Languages to show inline, or true for all
Code blocks for listed languages stay as normal <pre><code> blocks with Prism.js syntax highlighting. No artifact card, no panel, no extraction.
When a language matches both inlineCode and inlinePreview, inlineCode takes priority (no extraction).

Tabs & View Mode

Control which panel tabs are visible and the initial view mode, globally or per-message:
// Global config
provideArtifactuse({
  tabs: ['preview', 'code'],
  viewMode: 'code',
})
<!-- Or per-message override -->
<ArtifactuseAgentMessage
  :content="msg.content"
  :message-id="msg.id"
  :tabs="['code']"
  view-mode="code"
/>
Available tabs: 'preview', 'code', 'split', 'edit'. Available view modes match the tab names.

Config Precedence

All options support both global config and component prop levels. Precedence: Component prop → Global config → Default
// Global: all messages get code-only tabs
provideArtifactuse({ tabs: ['preview', 'code'] })

// Override: this specific message gets all tabs
<ArtifactuseAgentMessage :tabs="['preview', 'code', 'split', 'edit']" />

Form Collapse Behavior

Inline forms automatically collapse after user interaction to prevent duplicate submissions and keep the chat clean.

Form States

StateDescriptionVisual
activeInteractive, user can fill and submitFull form with fields
submittedUser clicked submit or action buttonCollapsed with ✓ checkmark
cancelledUser clicked cancelCollapsed with ✗ icon
inactiveHistorical form (page refresh)Collapsed with — dash

Behavior Rules

  • Current session: Forms stay active until user interacts
  • After submit/cancel/custom action: Form collapses immediately
  • After page refresh:
    • Last message forms stay active (via isLastMessage prop)
    • Older message forms collapse as inactive
  • Reset action: Form stays active (doesn’t collapse)

Example with isLastMessage

<template>
  <ArtifactuseAgentMessage 
    v-for="(msg, index) in messages"
    :key="msg.id"
    :content="msg.content"
    :message-id="msg.id"
    :is-last-message="index === messages.length - 1"
    @form-submit="handleFormSubmit"
  />
</template>

Media Lightbox

Images and PDFs automatically open in a fullscreen lightbox viewer when clicked. The viewer supports:
  • Zoom - Click image or zoom button to toggle zoom
  • Download - Download the original file
  • Keyboard - Press Escape to close
  • Click outside - Click overlay to close
<ArtifactuseAgentMessage 
  :content="content"
  :message-id="id"
  @media-open="({ type, src }) => console.log('Opened:', type, src)"
/>

Typing Indicator

Show a typing indicator while streaming AI responses:
<ArtifactuseAgentMessage 
  :content="partialContent"
  :message-id="id"
  :typing="isStreaming"
/>
The typing indicator displays animated loading bars that disappear when typing becomes false.

Example: Full Integration

<template>
  <div class="chat">
    <ArtifactuseAgentMessage 
      v-for="(msg, index) in messages"
      :key="msg.id"
      :content="msg.content"
      :message-id="msg.id"
      :typing="msg.isStreaming"
      :is-last-message="index === messages.length - 1"
      @form-submit="handleFormSubmit"
      @form-cancel="handleFormCancel"
      @form-button-click="handleFormButtonClick"
      @social-copy="handleSocialCopy"
      @media-open="handleMediaOpen"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { ArtifactuseAgentMessage } from 'artifactuse/vue'

const messages = ref([])

function handleFormSubmit({ formId, values }) {
  // Send form data back to AI
  sendToAI(`User submitted form: ${JSON.stringify(values)}`)
}

function handleFormCancel({ formId }) {
  // User cancelled the form
  console.log('Form cancelled:', formId)
}

function handleFormButtonClick({ formId, action, buttonName, values }) {
  // Handle custom button actions
  console.log('Button clicked:', buttonName, action)
}

function handleSocialCopy({ platform, text }) {
  // Track analytics
  analytics.track('social_copy', { platform })
}

function handleMediaOpen({ type, src }) {
  // Track media views
  analytics.track('media_view', { type, src })
}
</script>