chatmensaje
xph0000xUso
El componente ChatMessage representa un elemento <article> para un mensaje de chat user o assistant.
Partes
Utilice el prop parts para mostrar el contenido del mensaje utilizando el formato AI SDK.
<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 es el formato recomendado para el SDK de IA. Cada parte tiene un type (por ejemplo,'text') y el contenido correspondiente. El componente ChatMessage también admite el prop content obsoleto para compatibilidad con versiones anteriores.lado
Utilice el soporte side para mostrar el mensaje a la izquierda o a la derecha.
<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, el prop side se establece en left para mensajes assistant y right para mensajes user.Variante
Utilice el prop variant para cambiar el estilo del mensaje.
<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, el prop variant se establece en naked para los mensajes assistant y soft para los mensajes user.Color: badge{label="4.8+" class="align-text-top"} (en inglés)
Utilice el prop color para cambiar el color del mensaje.
<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
Utilice el prop icon para mostrar un componente Icon junto al mensaje.
<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 en Español
Utilice el prop avatar para mostrar un componente Avatar junto al mensaje.
<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>También puede utilizar el soporte avatar.icon para mostrar un icono como el avatar.
<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>Xph180xAcciones
Utilice el prop actions para mostrar las acciones debajo del mensaje que se mostrarán al pasar el cursor sobre el mensaje.
<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>Ejemplos
API (Versión)
Props (accesorios)
| 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 (Edición española)
| 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; } |
Temas
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'
}
}
}
})
]
})