ChatMessage
Display a chat message with icon, avatar, and actions.
Usage
The ChatMessage component renders an <article> element for a user or assistant chat message.
Parts
Use the parts prop to display the message content using the AI SDK format.
<template>
<PChatMessage
:parts="[
{
type: 'text',
id: '1',
text: 'Hello! Tell me more about building AI chatbots with Pohon UI.'
}
]"
role="user"
id="1"
/>
</template>The
parts prop is the recommended format for the AI SDK. Each part has a type (e.g. 'text') and corresponding content. The ChatMessage component also supports the deprecated content prop for backward compatibility.Side
Use the side prop to display the message on the left or right.
<template>
<PChatMessage
side="right"
:parts="[
{
type: 'text',
id: '1',
text: 'Hello! Tell me more about building AI chatbots with Pohon UI.'
}
]"
role="user"
id="1"
/>
</template>When using the
ChatMessages component, the side prop is set to left for assistant messages and right for user messages.Variant
Use the variant prop to change style of the message.
<template>
<PChatMessage
variant="soft"
:parts="[
{
type: 'text',
id: '1',
text: 'Hello! Tell me more about building AI chatbots with Pohon UI.'
}
]"
role="user"
id="1"
/>
</template>When using the
ChatMessages component, the variant prop is set to naked for assistant messages and soft for user messages.Color
Use the color prop to change the color of the message.
<template>
<PChatMessage
variant="soft"
color="primary"
:parts="[
{
type: 'text',
id: '1',
text: 'Hello! Tell me more about building AI chatbots with Pohon UI.'
}
]"
role="user"
id="1"
/>
</template>Icon
Use the icon prop to display an Icon component next to the message.
<template>
<PChatMessage
icon="i-lucide-user"
variant="soft"
side="right"
:parts="[
{
type: 'text',
id: '1',
text: 'Hello! Tell me more about building AI chatbots with Pohon UI.'
}
]"
role="user"
id="1"
/>
</template>Avatar
Use the avatar prop to display an Avatar component next to the message.
<template>
<PChatMessage
: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 Pohon UI.'
}
]"
role="user"
id="1"
/>
</template>You can also use the avatar.icon prop to display an icon as the avatar.
<template>
<PChatMessage
:avatar="{
icon: 'i-lucide-bot'
}"
:parts="[
{
type: 'text',
id: '1',
text: 'Pohon 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
Use the actions prop to display actions below the message that will be displayed when hovering over the message.
<script setup lang="ts">
import type { ButtonProps } from 'pohon-ui'
const actions = ref<ButtonProps[]>([
{
label: 'Copy to clipboard',
icon: 'i-lucide-copy'
}
])
</script>
<template>
<PChatMessage
:actions="actions"
:parts="[
{
type: 'text',
id: '1',
text: 'Pohon 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 'pohon-ui'
const actions = ref<ButtonProps[]>([
{
label: 'Copy to clipboard',
icon: 'i-lucide-copy'
}
])
</script>
<template>
<PChatMessage
:actions="actions"
:parts="[
{
type: 'text',
id: '1',
text: 'Pohon 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>Examples
API
Props
| Prop | Default | Type |
|---|
Slots
| Slot | Type |
|---|
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 flex-wrap items-center gap-1.5',
content: 'relative text-pretty wrap-break-word *:first:mt-0 *:last:mb-0',
actions: [
'flex items-center bottom-0 absolute [@media(hover:hover)]:opacity-0 group-hover/message:opacity-100 focus-within:opacity-100',
'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: 'end-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 color-primary-foreground'
}
},
{
color: 'primary',
variant: 'outline',
class: {
content: 'color-primary ring ring-primary/25'
}
},
{
color: 'primary',
variant: 'soft',
class: {
content: 'bg-primary/10 color-primary'
}
},
{
color: 'primary',
variant: 'subtle',
class: {
content: 'bg-primary/10 color-primary ring ring-primary/25'
}
},
{
color: 'primary',
variant: 'naked',
class: {
content: 'color-primary'
}
},
{
color: 'neutral',
variant: 'solid',
class: {
content: 'bg-background-inverted color-text-inverted'
}
},
{
color: 'neutral',
variant: 'outline',
class: {
content: 'bg-background ring ring-border'
}
},
{
color: 'neutral',
variant: 'soft',
class: {
content: 'bg-background-elevated/50'
}
},
{
color: 'neutral',
variant: 'subtle',
class: {
content: 'bg-background-elevated/50 ring ring-border'
}
}
],
defaultVariants: {
side: 'left',
variant: 'naked',
color: 'neutral'
}
}
}
})vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from 'pohon-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 flex-wrap items-center gap-1.5',
content: 'relative text-pretty wrap-break-word *:first:mt-0 *:last:mb-0',
actions: [
'flex items-center bottom-0 absolute [@media(hover:hover)]:opacity-0 group-hover/message:opacity-100 focus-within:opacity-100',
'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: 'end-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 color-primary-foreground'
}
},
{
color: 'primary',
variant: 'outline',
class: {
content: 'color-primary ring ring-primary/25'
}
},
{
color: 'primary',
variant: 'soft',
class: {
content: 'bg-primary/10 color-primary'
}
},
{
color: 'primary',
variant: 'subtle',
class: {
content: 'bg-primary/10 color-primary ring ring-primary/25'
}
},
{
color: 'primary',
variant: 'naked',
class: {
content: 'color-primary'
}
},
{
color: 'neutral',
variant: 'solid',
class: {
content: 'bg-background-inverted color-text-inverted'
}
},
{
color: 'neutral',
variant: 'outline',
class: {
content: 'bg-background ring ring-border'
}
},
{
color: 'neutral',
variant: 'soft',
class: {
content: 'bg-background-elevated/50'
}
},
{
color: 'neutral',
variant: 'subtle',
class: {
content: 'bg-background-elevated/50 ring ring-border'
}
}
],
defaultVariants: {
side: 'left',
variant: 'naked',
color: 'neutral'
}
}
}
})
]
})Changelog
No recent changes