ChatMessage 대화

아이콘, 아바타 및 동작이 포함된 대화 메시지를 표시합니다.

Usage

ChatMessage 구성 요소는 user 또는 assistant 채팅 메시지에 대한 <article> 요소를 렌더링합니다.

Hello! Tell me more about building AI chatbots with Nuxt UI.
ChatMessages 구성 요소를 사용하여 대화 메시지 목록을 표시합니다.

Parts 부품

parts prop를 사용하여 AI SDK 형식을 사용하여 메시지 내용을 표시합니다.

Hello! Tell me more about building AI chatbots with Nuxt UI.
<template>
  <UChatMessage
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>
parts prop은 AI SDK에 권장되는 형식입니다. 각 부분에는 type(예: 'text')와 해당 내용이 있습니다. ChatMessage 구성 요소는 이전 버전과의 호환성을 위해 더 이상 사용되지 않는 content prop도 지원합니다.

Side 사이드

side prop을 사용하여 메시지를 왼쪽이나 오른쪽에 표시합니다.

Hello! Tell me more about building AI chatbots with Nuxt UI.
<template>
  <UChatMessage
    side="right"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>
ChatMessages 구성 요소를 사용하는 경우 side 소품은 assistant 메시지의 경우 left로, user 메시지의 경우 right로 설정됩니다.

변형

variant prop을 사용하여 메시지의 스타일을 변경합니다.

Hello! Tell me more about building AI chatbots with Nuxt UI.
<template>
  <UChatMessage
    variant="soft"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>
ChatMessages 구성 요소를 사용하는 경우 variant 소품은 assistant 메시지의 경우 naked, user 메시지의 경우 soft로 설정됩니다.

Color : badge{label="4.8+" class="align-text-top"}

color prop을 사용하여 메시지 색상을 변경합니다.

Hello! Tell me more about building AI chatbots with Nuxt UI.
<template>
  <UChatMessage
    variant="soft"
    color="primary"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>

Icon

icon prop을 사용하여 메시지 옆에 Icon 구성 요소를 표시합니다.

Hello! Tell me more about building AI chatbots with Nuxt UI.
<template>
  <UChatMessage
    icon="i-lucide-user"
    variant="soft"
    side="right"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>

avatar 이미지

avatar prop을 사용하여 메시지 옆에 Avatar 구성 요소를 표시합니다.

Hello! Tell me more about building AI chatbots with Nuxt UI.
<template>
  <UChatMessage
    :avatar="{
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy'
    }"
    variant="soft"
    side="right"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Hello! Tell me more about building AI chatbots with Nuxt UI.'
      }
    ]"
    role="user"
    id="1"
  />
</template>

avatar.icon prop을 사용하여 아이콘을 아바타로 표시할 수도 있습니다.

Nuxt UI offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the Chat class from AI SDK, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design.
<template>
  <UChatMessage
    :avatar="{
      icon: 'i-lucide-bot'
    }"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Nuxt UI offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the Chat class from AI SDK, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design.'
      }
    ]"
    role="assistant"
    id="1"
  />
</template>

Actions (### 액션)

actions 소품을 사용하여 메시지 위에 마우스를 놓을 때 표시될 메시지 아래에 액션을 표시합니다.

Nuxt UI offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the Chat class from AI SDK, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design.
<script setup lang="ts">
import type { ButtonProps } from '@nuxt/ui'

const actions = ref<ButtonProps[]>([
  {
    label: 'Copy to clipboard',
    icon: 'i-lucide-copy'
  }
])
</script>

<template>
  <UChatMessage
    :actions="actions"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Nuxt UI offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the Chat class from AI SDK, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design.'
      }
    ]"
    role="user"
    id="1"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ButtonProps } from '@nuxt/ui'

const actions = ref<ButtonProps[]>([
  {
    label: 'Copy to clipboard',
    icon: 'i-lucide-copy'
  }
])
</script>

<template>
  <UChatMessage
    :actions="actions"
    :parts="[
      {
        type: 'text',
        id: '1',
        text: 'Nuxt UI offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the Chat class from AI SDK, implementing proper message styling with variants, and utilizing the built-in actions for message interactions. The components are fully customizable with theming support and responsive design.'
      }
    ]"
    role="user"
    id="1"
  />
</template>

예제

Chat 개요 페이지에서 설치 지침, 서버 설정 및 사용 예를 확인하십시오.

API 파일

Props (### Props)

Prop Default Type
as
'article'
any

The element or component this component should render as.

id
string

A unique identifier for the message.

role
"system" | "user" | "assistant"

The role of the message.

parts
UIMessagePart<TDataParts, TTools>[]

The parts of the message. Use this for rendering the message in the UI.

System messages should be avoided (set the system prompt on the server instead). They can have text parts.

User messages can have text parts and file parts.

Assistant messages can have text, reasoning, tool invocation, and file parts.

icon
any
avatar
AvatarProps & { [key: string]: any; }
variant
'naked'
"solid" | "outline" | "soft" | "subtle" | "naked"
color
'neutral'
"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
side
'left'
"left" | "right"
actions
(Omit<ButtonProps, "onClick"> & { onClick?: ((e: MouseEvent, message: UIMessage<TMetadata, TDataParts, TTools>) => void) | undefined; })[]

Display a list of actions under the message. The label will be used in a tooltip. { size: 'xs', color: 'neutral', variant: 'ghost' }

compact
false
boolean

Render the message in a compact style. This is done automatically when used inside a UChatPalette.

content
string
metadata
TMetadata

The metadata of the message.

ui
{ root?: SlotClass; header?: SlotClass; container?: SlotClass; body?: SlotClass; leading?: SlotClass; leadingIcon?: SlotClass; leadingAvatar?: SlotClass; leadingAvatarSize?: SlotClass; files?: SlotClass; content?: SlotClass; actions?: SlotClass; }

슬롯

Slot Type
header
UIMessage<TMetadata, TDataParts, TTools>
leading
UIMessage<TMetadata, TDataParts, TTools> & { avatar: (AvatarProps & { [key: string]: any; }) | undefined; ui: object; }
files
Omit<UIMessage<TMetadata, TDataParts, TTools>, "parts"> & { parts: FileUIPart[]; }
body
UIMessage<TMetadata, TDataParts, TTools>
content
UIMessage<TMetadata, TDataParts, TTools> & { content?: string | undefined; }
actions
UIMessage<TMetadata, TDataParts, TTools> & { actions: (Omit<ButtonProps, "onClick"> & { onClick?: ((e: MouseEvent, message: UIMessage<TMetadata, TDataParts, TTools>) => void) | undefined; })[] | undefined; }

Theme 테마

app.config.ts
export default defineAppConfig({
  ui: {
    chatMessage: {
      slots: {
        root: 'group/message relative w-full',
        header: 'flex mb-1.5',
        container: 'relative flex items-start',
        body: 'min-w-0',
        leading: 'inline-flex items-center justify-center min-h-6',
        leadingIcon: 'shrink-0',
        leadingAvatar: 'shrink-0',
        leadingAvatarSize: '',
        files: 'flex items-center gap-1.5',
        content: 'relative text-pretty wrap-break-word *:first:mt-0 *:last:mb-0',
        actions: [
          '[@media(hover:hover)]:opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
          'transition-opacity ease-out'
        ]
      },
      variants: {
        variant: {
          solid: '',
          outline: '',
          soft: '',
          subtle: '',
          naked: ''
        },
        color: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        side: {
          left: {},
          right: {
            container: 'justify-end ms-auto max-w-[75%]',
            header: 'justify-end',
            actions: 'right-0'
          }
        },
        leading: {
          true: ''
        },
        actions: {
          true: ''
        },
        compact: {
          true: {
            root: 'scroll-mt-3',
            container: 'gap-1.5 pb-3',
            content: 'space-y-2',
            leadingIcon: 'size-5',
            leadingAvatarSize: '2xs'
          },
          false: {
            root: 'scroll-mt-4 sm:scroll-mt-6',
            container: 'gap-3 pb-8',
            content: 'space-y-4',
            leadingIcon: 'size-8',
            leadingAvatarSize: 'md'
          }
        }
      },
      compoundVariants: [
        {
          compact: true,
          actions: true,
          class: {
            container: 'pb-8'
          }
        },
        {
          variant: [
            'solid',
            'outline',
            'soft',
            'subtle'
          ],
          compact: false,
          class: {
            content: 'px-4 py-3 rounded-lg min-h-12',
            leading: 'mt-2'
          }
        },
        {
          variant: [
            'solid',
            'outline',
            'soft',
            'subtle'
          ],
          compact: true,
          class: {
            content: 'px-2 py-1 rounded-lg min-h-8',
            leading: 'mt-1'
          }
        },
        {
          variant: 'naked',
          side: 'left',
          class: {
            body: 'w-full',
            content: 'w-full'
          }
        },
        {
          color: 'primary',
          variant: 'solid',
          class: {
            content: 'bg-primary text-inverted'
          }
        },
        {
          color: 'primary',
          variant: 'outline',
          class: {
            content: 'text-primary ring ring-primary/25'
          }
        },
        {
          color: 'primary',
          variant: 'soft',
          class: {
            content: 'bg-primary/10 text-primary'
          }
        },
        {
          color: 'primary',
          variant: 'subtle',
          class: {
            content: 'bg-primary/10 text-primary ring ring-primary/25'
          }
        },
        {
          color: 'primary',
          variant: 'naked',
          class: {
            content: 'text-primary'
          }
        },
        {
          color: 'neutral',
          variant: 'solid',
          class: {
            content: 'bg-inverted text-inverted'
          }
        },
        {
          color: 'neutral',
          variant: 'outline',
          class: {
            content: 'bg-default ring ring-default'
          }
        },
        {
          color: 'neutral',
          variant: 'soft',
          class: {
            content: 'bg-elevated/50'
          }
        },
        {
          color: 'neutral',
          variant: 'subtle',
          class: {
            content: 'bg-elevated/50 ring ring-default'
          }
        }
      ],
      defaultVariants: {
        side: 'left',
        variant: 'naked',
        color: 'neutral'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        chatMessage: {
          slots: {
            root: 'group/message relative w-full',
            header: 'flex mb-1.5',
            container: 'relative flex items-start',
            body: 'min-w-0',
            leading: 'inline-flex items-center justify-center min-h-6',
            leadingIcon: 'shrink-0',
            leadingAvatar: 'shrink-0',
            leadingAvatarSize: '',
            files: 'flex items-center gap-1.5',
            content: 'relative text-pretty wrap-break-word *:first:mt-0 *:last:mb-0',
            actions: [
              '[@media(hover:hover)]:opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
              'transition-opacity ease-out'
            ]
          },
          variants: {
            variant: {
              solid: '',
              outline: '',
              soft: '',
              subtle: '',
              naked: ''
            },
            color: {
              primary: '',
              secondary: '',
              success: '',
              info: '',
              warning: '',
              error: '',
              neutral: ''
            },
            side: {
              left: {},
              right: {
                container: 'justify-end ms-auto max-w-[75%]',
                header: 'justify-end',
                actions: 'right-0'
              }
            },
            leading: {
              true: ''
            },
            actions: {
              true: ''
            },
            compact: {
              true: {
                root: 'scroll-mt-3',
                container: 'gap-1.5 pb-3',
                content: 'space-y-2',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs'
              },
              false: {
                root: 'scroll-mt-4 sm:scroll-mt-6',
                container: 'gap-3 pb-8',
                content: 'space-y-4',
                leadingIcon: 'size-8',
                leadingAvatarSize: 'md'
              }
            }
          },
          compoundVariants: [
            {
              compact: true,
              actions: true,
              class: {
                container: 'pb-8'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: false,
              class: {
                content: 'px-4 py-3 rounded-lg min-h-12',
                leading: 'mt-2'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: true,
              class: {
                content: 'px-2 py-1 rounded-lg min-h-8',
                leading: 'mt-1'
              }
            },
            {
              variant: 'naked',
              side: 'left',
              class: {
                body: 'w-full',
                content: 'w-full'
              }
            },
            {
              color: 'primary',
              variant: 'solid',
              class: {
                content: 'bg-primary text-inverted'
              }
            },
            {
              color: 'primary',
              variant: 'outline',
              class: {
                content: 'text-primary ring ring-primary/25'
              }
            },
            {
              color: 'primary',
              variant: 'soft',
              class: {
                content: 'bg-primary/10 text-primary'
              }
            },
            {
              color: 'primary',
              variant: 'subtle',
              class: {
                content: 'bg-primary/10 text-primary ring ring-primary/25'
              }
            },
            {
              color: 'primary',
              variant: 'naked',
              class: {
                content: 'text-primary'
              }
            },
            {
              color: 'neutral',
              variant: 'solid',
              class: {
                content: 'bg-inverted text-inverted'
              }
            },
            {
              color: 'neutral',
              variant: 'outline',
              class: {
                content: 'bg-default ring ring-default'
              }
            },
            {
              color: 'neutral',
              variant: 'soft',
              class: {
                content: 'bg-elevated/50'
              }
            },
            {
              color: 'neutral',
              variant: 'subtle',
              class: {
                content: 'bg-elevated/50 ring ring-default'
              }
            }
          ],
          defaultVariants: {
            side: 'left',
            variant: 'naked',
            color: 'neutral'
          }
        }
      }
    })
  ]
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitHub.

변경 로그

No recent changes