ChatBericht
Gebruik
Het ChatMessage-onderdeel geeft een <article>-element weer voor een user of assistant chatbericht.
Onderdelen
Gebruik de parts prop om de berichtinhoud weer te geven met behulp van de AI SDK-indeling.
<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 is het aanbevolen formaat voor de AI SDK. Elk onderdeel heeft een type (bijv. 'tekst') en bijbehorende inhoud.
De ChatMessage-component ondersteunt ook de verouderde content-prop voor achterwaartse compatibiliteit.Zijde
Gebruik de side prop om het bericht links of rechts weer te geven.
<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 is de side prop ingesteld op left voor assistant berichten en right voor user berichten.Variant
Gebruik de variant prop om de stijl van het bericht te wijzigen.
<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 component wordt de variant prop ingesteld op naked voor assistant berichten en soft voor user berichten.Kleur: badge{label="4.8+" class="align-text-top"}
Gebruik de color prop om de kleur van het bericht te wijzigen.
<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>Icoon
Gebruik de icon prop om een Icon naast het bericht weer te geven.
<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
Gebruik de avatar prop om een Avatar naast het bericht weer te geven.
<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>U kunt ook de avatar.icon prop gebruiken om een pictogram als avatar weer te geven.
<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>Acties
Gebruik de actions-prop om acties onder het bericht weer te geven die worden weergegeven wanneer u met de muisaanwijzer over het bericht beweegt.
<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>Voorbeelden
API
Props
| Prop | Default | Type |
|---|---|---|
as | 'article' | anyThe element or component this component should render as. |
id | stringA 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 | |
compact | false | boolean Render the message in a compact style.
This is done automatically when used inside a |
content | string | |
metadata | TMetadataThe 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; } |
Slots
| 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; } |
Thema
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'
}
}
}
})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'
}
}
}
})
]
})