> ## Documentation Index
> Fetch the complete documentation index at: https://artifactuse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# ArtifactuseAgentMessage

> Render AI messages with automatic artifact detection

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

## Import

<Tabs>
  <Tab title="Vue 3">
    ```js theme={null}
    import { ArtifactuseAgentMessage } from 'artifactuse/vue'
    ```
  </Tab>

  <Tab title="Vue 2">
    ```js theme={null}
    import { ArtifactuseAgentMessage } from 'artifactuse/vue2'
    ```
  </Tab>

  <Tab title="React">
    ```js theme={null}
    import { ArtifactuseAgentMessage } from 'artifactuse/react'
    ```
  </Tab>

  <Tab title="Svelte">
    ```js theme={null}
    import { ArtifactuseAgentMessage } from 'artifactuse/svelte'
    ```
  </Tab>
</Tabs>

## Usage

<Tabs>
  <Tab title="Vue">
    ```vue theme={null}
    <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>
    ```
  </Tab>

  <Tab title="React">
    ```jsx theme={null}
    <ArtifactuseAgentMessage 
      content={message.content}
      messageId={message.id}
      typing={isStreaming}
      isLastMessage={isLastMessage}
      onArtifactDetected={onDetected}
      onArtifactOpen={onOpen}
      onFormSubmit={onFormSubmit}
      onFormCancel={onFormCancel}
      onFormButtonClick={onFormButtonClick}
      onSocialCopy={onSocialCopy}
      onMediaOpen={onMediaOpen}
    />
    ```
  </Tab>

  <Tab title="Svelte">
    ```svelte theme={null}
    <ArtifactuseAgentMessage 
      content={message.content}
      messageId={message.id}
      typing={isStreaming}
      isLastMessage={isLastMessage}
      on:artifact-detected={onDetected}
      on:artifact-open={onOpen}
      on:form-submit={onFormSubmit}
      on:form-cancel={onFormCancel}
      on:form-button-click={onFormButtonClick}
      on:social-copy={onSocialCopy}
      on:media-open={onMediaOpen}
    />
    ```
  </Tab>
</Tabs>

## Props

| Prop            | Type       | Default  | Description                                                                                 |
| --------------- | ---------- | -------- | ------------------------------------------------------------------------------------------- |
| `content`       | `string`   | Required | Raw message content from AI (Markdown, code blocks, JSON artifacts)                         |
| `messageId`     | `string`   | Required | Unique identifier for the message                                                           |
| `typing`        | `boolean`  | `false`  | Show typing indicator (use while streaming)                                                 |
| `inlineCards`   | `boolean`  | `true`   | Show clickable cards for panel artifacts inline. Also configurable globally.                |
| `isLastMessage` | `boolean`  | `false`  | Whether this is the last message in the conversation. Keeps forms active after page reload. |
| `inlinePreview` | `object`   | `null`   | Override global `inlinePreview` config for this message                                     |
| `inlineCode`    | `object`   | `null`   | Override global `inlineCode` config for this message                                        |
| `tabs`          | `string[]` | `null`   | Override visible panel tabs for artifacts from this message                                 |
| `viewMode`      | `string`   | `null`   | Override initial panel view mode for artifacts from this message                            |

## Events

| Event               | Payload                                                          | Description                                           |
| ------------------- | ---------------------------------------------------------------- | ----------------------------------------------------- |
| `artifact-detected` | `Artifact[]`                                                     | Fired when artifacts are detected in content          |
| `artifact-open`     | `Artifact`                                                       | Fired 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     |

<Note>
  Event names use kebab-case in Vue (`@form-submit`) and camelCase in React (`onFormSubmit`). Svelte uses kebab-case with `on:` prefix (`on:form-submit`).
</Note>

## Artifact Rendering

The component automatically renders different artifact types:

| Artifact Type                   | Rendering                           |
| ------------------------------- | ----------------------------------- |
| `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     |
| `social`                        | Inline social media preview         |
| Images                          | Inline with lightbox on click       |
| Videos                          | Inline embed (YouTube, Vimeo, etc.) |
| Other embeds                    | Inline (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:

```js theme={null}
// Global config
provideArtifactuse({
  inlinePreview: {
    maxLines: 15,
    languages: ['smartdiff', 'html', 'javascript', 'jsx'],
  },
})
```

```vue theme={null}
<!-- Or per-message override -->
<ArtifactuseAgentMessage
  :content="msg.content"
  :message-id="msg.id"
  :inline-preview="{ maxLines: 10, languages: ['html'] }"
/>
```

| Option              | Type                 | Default | Description                                                                                |
| ------------------- | -------------------- | ------- | ------------------------------------------------------------------------------------------ |
| `maxLines`          | `number`             | `15`    | Max lines to show before truncation                                                        |
| `languages`         | `string[]` or `true` | `[]`    | Languages to show inline preview for, or `true` for all                                    |
| `excludeLanguages`  | `string[]`           | `[]`    | Languages to exclude from inline preview (used with `languages: true`)                     |
| `minClickableLines` | `number` or `object` | `null`  | Disable clicking for short code blocks. Number shorthand or `{ lines, ignoreLanguages }`   |
| `actionLabel`       | `string` or `object` | `null`  | Customize 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.

<Note>
  Inline code preview requires [Prism.js](https://prismjs.com/) for syntax highlighting. Load Prism and language grammars via CDN or npm.
</Note>

### Exclude Languages

When using `languages: true`, exclude specific languages from inline preview with `excludeLanguages`. Excluded languages fall back to artifact cards:

```js theme={null}
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:

```js theme={null}
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:

```js theme={null}
minClickableLines: {
  lines: 10,
  ignoreLanguages: ['html', 'markdown', 'jsx', 'vue'],
},
```

### Custom Action Labels

Customize the fade overlay label text per language:

```js theme={null}
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:

```js theme={null}
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`:

```js theme={null}
// Global config
provideArtifactuse({
  inlineCode: {
    languages: ['css', 'bash', 'sql'],  // or true for all
  },
})
```

```vue theme={null}
<!-- Or per-message override -->
<ArtifactuseAgentMessage
  :content="msg.content"
  :message-id="msg.id"
  :inline-code="{ languages: true }"
/>
```

| Option      | Type                 | Default | Description                                 |
| ----------- | -------------------- | ------- | ------------------------------------------- |
| `languages` | `string[]` 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.

<Note>
  When a language matches both `inlineCode` and `inlinePreview`, `inlineCode` takes priority (no extraction).
</Note>

## Tabs & View Mode

Control which panel tabs are visible and the initial view mode, globally or per-message:

```js theme={null}
// Global config
provideArtifactuse({
  tabs: ['preview', 'code'],
  viewMode: 'code',
})
```

```vue theme={null}
<!-- 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**

```js theme={null}
// 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

| State       | Description                           | Visual                     |
| ----------- | ------------------------------------- | -------------------------- |
| `active`    | Interactive, user can fill and submit | Full form with fields      |
| `submitted` | User clicked submit or action button  | Collapsed with ✓ checkmark |
| `cancelled` | User clicked cancel                   | Collapsed with ✗ icon      |
| `inactive`  | Historical 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

```vue theme={null}
<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

```vue theme={null}
<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:

```vue theme={null}
<ArtifactuseAgentMessage 
  :content="partialContent"
  :message-id="id"
  :typing="isStreaming"
/>
```

The typing indicator displays animated loading bars that disappear when `typing` becomes `false`.

## Example: Full Integration

<Tabs>
  <Tab title="Vue">
    ```vue theme={null}
    <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>
    ```
  </Tab>

  <Tab title="React">
    ```jsx theme={null}
    import { useState } from 'react'
    import { ArtifactuseAgentMessage } from 'artifactuse/react'

    function Chat() {
      const [messages, setMessages] = useState([])

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

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

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

      const handleSocialCopy = ({ platform, text }) => {
        // Track analytics
        analytics.track('social_copy', { platform })
      }

      const handleMediaOpen = ({ type, src }) => {
        // Track media views
        analytics.track('media_view', { type, src })
      }

      return (
        <div className="chat">
          {messages.map((msg, index) => (
            <ArtifactuseAgentMessage 
              key={msg.id}
              content={msg.content}
              messageId={msg.id}
              typing={msg.isStreaming}
              isLastMessage={index === messages.length - 1}
              onFormSubmit={handleFormSubmit}
              onFormCancel={handleFormCancel}
              onFormButtonClick={handleFormButtonClick}
              onSocialCopy={handleSocialCopy}
              onMediaOpen={handleMediaOpen}
            />
          ))}
        </div>
      )
    }
    ```
  </Tab>
</Tabs>
