ChatMessagePRO

Display a chat message with icon, avatar, and actions.

Usage

The ChatMessage component renders an <article> element for a user or assistant chat message.

Hello! Tell me more about building AI chatbots with Nuxt UI Pro.
Use the ChatMessages component to display a list of chat messages.

Content

Use the content prop to display the message content.

Hello! Tell me more about building AI chatbots with Nuxt UI Pro.
<template>
  <UChatMessage content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro." />
</template>

Side

Use the side prop to display the message on the left or right.

Hello! Tell me more about building AI chatbots with Nuxt UI Pro.
<template>
  <UChatMessage
    side="right"
    content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro."
  />
</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.

Hello! Tell me more about building AI chatbots with Nuxt UI Pro.
<template>
  <UChatMessage
    variant="soft"
    content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro."
  />
</template>
When using the ChatMessages component, the variant prop is set to naked for assistant messages and soft for user messages.

Icon

Use the icon prop to display an Icon component next to the message.

Hello! Tell me more about building AI chatbots with Nuxt UI Pro.
<template>
  <UChatMessage
    icon="i-lucide-user"
    variant="soft"
    side="right"
    content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro."
  />
</template>

Avatar

Use the avatar prop to display an Avatar component next to the message.

Hello! Tell me more about building AI chatbots with Nuxt UI Pro.
<template>
  <UChatMessage
    :avatar="{
      src: 'https://github.com/benjamincanac.png'
    }"
    variant="soft"
    side="right"
    content="Hello! Tell me more about building AI chatbots with Nuxt UI Pro."
  />
</template>

You can also use the avatar.icon prop to display an icon as the avatar.

Nuxt UI Pro offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the useChat composable from Vercel 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'
    }"
    content="Nuxt UI Pro offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the useChat composable from Vercel 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>

Actions

Use the actions prop to display actions below the message that will be displayed when hovering over the message.

Nuxt UI Pro offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the useChat composable from Vercel 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">
const actions = ref([
  {
    label: 'Copy to clipboard',
    icon: 'i-lucide-copy'
  }
])
</script>

<template>
  <UChatMessage
    :actions="actions"
    content="Nuxt UI Pro offers several features for building AI chatbots including the ChatMessage, ChatMessages, and ChatPrompt components. Best practices include using the useChat composable from Vercel 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>

API

Props

Prop Default Type
as

'article'

any

content

string

Text content of the message. Use parts when possible.

id

string

A unique identifier for the message.

role

"data" | "user" | "system" | "assistant"

The 'data' role is deprecated.

icon

string

avatar

AvatarProps & { [key: string]: any; }

variant

'naked'

"outline" | "solid" | "subtle" | "soft" | "naked"

side

'left'

"right" | "left"

data

null | string | number | false | true | { [value: string]: JSONValue; } | JSONValue[]

For data messages.

actions

(Omit<ButtonProps, "onClick"> & { onClick?: ((e: MouseEvent, message: Message) => 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.

createdAt

Date

The timestamp of the message.

reasoning

string

Reasoning for the message.

experimental_attachments

Attachment[]

Additional attachments to be sent along with the message.

annotations

JSONValue[]

Additional message-specific information added on the server via StreamData

toolInvocations

ToolInvocation[]

Tool invocations (that can be tool calls or tool results, depending on whether or not the invocation has finished) that the assistant made as part of this message.

parts

(TextUIPart | ReasoningUIPart | ToolInvocationUIPart | SourceUIPart | FileUIPart | StepStartUIPart)[]

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

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

ui

{ root?: ClassNameValue; container?: ClassNameValue; leading?: ClassNameValue; leadingIcon?: ClassNameValue; leadingAvatar?: ClassNameValue; leadingAvatarSize?: ClassNameValue; content?: ClassNameValue; actions?: ClassNameValue; }

Slots

Slot Type
leading

{ avatar: (AvatarProps & { [key: string]: any; }) | undefined; }

content

{ content: string; }

actions

{ actions: (Omit<ButtonProps, "onClick"> & { onClick?: ((e: MouseEvent, message: Message) => void) | undefined; })[] | undefined; }

Theme

app.config.ts
export default defineAppConfig({
  uiPro: {
    chatMessage: {
      slots: {
        root: 'group/message relative w-full',
        container: 'relative flex items-start group-data-[role=user]/message:max-w-[75%]',
        leading: 'inline-flex items-center justify-center min-h-6',
        leadingIcon: 'shrink-0',
        leadingAvatar: 'shrink-0',
        leadingAvatarSize: '',
        content: 'relative text-pretty',
        actions: [
          'opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
          'transition-opacity'
        ]
      },
      variants: {
        variant: {
          solid: {
            content: 'bg-(--ui-bg-inverted) text-(--ui-bg)'
          },
          outline: {
            content: 'bg-(--ui-bg) ring ring-(--ui-border)'
          },
          soft: {
            content: 'bg-(--ui-bg-elevated)/50'
          },
          subtle: {
            content: 'bg-(--ui-bg-elevated)/50 ring ring-(--ui-border)'
          },
          naked: {
            content: ''
          }
        },
        side: {
          left: {
            container: 'rtl:justify-end'
          },
          right: {
            container: 'ltr:justify-end ms-auto'
          }
        },
        leading: {
          true: ''
        },
        actions: {
          true: ''
        },
        compact: {
          true: {
            root: 'scroll-mt-3',
            container: 'gap-1.5 pb-3',
            leadingIcon: 'size-5',
            leadingAvatarSize: '2xs'
          },
          false: {
            root: 'scroll-mt-4 sm:scroll-mt-6',
            container: 'gap-3 pb-8',
            leadingIcon: 'size-8',
            leadingAvatarSize: 'md'
          }
        }
      },
      compoundVariants: [
        {
          compact: true,
          actions: true,
          class: {
            container: 'pb-8'
          }
        },
        {
          leading: true,
          compact: false,
          side: 'left',
          class: {
            actions: 'left-11'
          }
        },
        {
          leading: true,
          compact: true,
          side: 'left',
          class: {
            actions: 'left-6.5'
          }
        },
        {
          variant: [
            'solid',
            'outline',
            'soft',
            'subtle'
          ],
          compact: false,
          class: {
            content: 'px-4 py-3 rounded-[calc(var(--ui-radius)*2)] min-h-12',
            leading: 'mt-2'
          }
        },
        {
          variant: [
            'solid',
            'outline',
            'soft',
            'subtle'
          ],
          compact: true,
          class: {
            content: 'px-2 py-1 rounded-[calc(var(--ui-radius)*2)] min-h-8',
            leading: 'mt-1'
          }
        }
      ],
      defaultVariants: {
        variant: 'naked'
      }
    }
  }
})
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({
      uiPro: {
        chatMessage: {
          slots: {
            root: 'group/message relative w-full',
            container: 'relative flex items-start group-data-[role=user]/message:max-w-[75%]',
            leading: 'inline-flex items-center justify-center min-h-6',
            leadingIcon: 'shrink-0',
            leadingAvatar: 'shrink-0',
            leadingAvatarSize: '',
            content: 'relative text-pretty',
            actions: [
              'opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
              'transition-opacity'
            ]
          },
          variants: {
            variant: {
              solid: {
                content: 'bg-(--ui-bg-inverted) text-(--ui-bg)'
              },
              outline: {
                content: 'bg-(--ui-bg) ring ring-(--ui-border)'
              },
              soft: {
                content: 'bg-(--ui-bg-elevated)/50'
              },
              subtle: {
                content: 'bg-(--ui-bg-elevated)/50 ring ring-(--ui-border)'
              },
              naked: {
                content: ''
              }
            },
            side: {
              left: {
                container: 'rtl:justify-end'
              },
              right: {
                container: 'ltr:justify-end ms-auto'
              }
            },
            leading: {
              true: ''
            },
            actions: {
              true: ''
            },
            compact: {
              true: {
                root: 'scroll-mt-3',
                container: 'gap-1.5 pb-3',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs'
              },
              false: {
                root: 'scroll-mt-4 sm:scroll-mt-6',
                container: 'gap-3 pb-8',
                leadingIcon: 'size-8',
                leadingAvatarSize: 'md'
              }
            }
          },
          compoundVariants: [
            {
              compact: true,
              actions: true,
              class: {
                container: 'pb-8'
              }
            },
            {
              leading: true,
              compact: false,
              side: 'left',
              class: {
                actions: 'left-11'
              }
            },
            {
              leading: true,
              compact: true,
              side: 'left',
              class: {
                actions: 'left-6.5'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: false,
              class: {
                content: 'px-4 py-3 rounded-[calc(var(--ui-radius)*2)] min-h-12',
                leading: 'mt-2'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: true,
              class: {
                content: 'px-2 py-1 rounded-[calc(var(--ui-radius)*2)] min-h-8',
                leading: 'mt-1'
              }
            }
          ],
          defaultVariants: {
            variant: 'naked'
          }
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      uiPro: {
        chatMessage: {
          slots: {
            root: 'group/message relative w-full',
            container: 'relative flex items-start group-data-[role=user]/message:max-w-[75%]',
            leading: 'inline-flex items-center justify-center min-h-6',
            leadingIcon: 'shrink-0',
            leadingAvatar: 'shrink-0',
            leadingAvatarSize: '',
            content: 'relative text-pretty',
            actions: [
              'opacity-0 group-hover/message:opacity-100 absolute bottom-0 flex items-center',
              'transition-opacity'
            ]
          },
          variants: {
            variant: {
              solid: {
                content: 'bg-(--ui-bg-inverted) text-(--ui-bg)'
              },
              outline: {
                content: 'bg-(--ui-bg) ring ring-(--ui-border)'
              },
              soft: {
                content: 'bg-(--ui-bg-elevated)/50'
              },
              subtle: {
                content: 'bg-(--ui-bg-elevated)/50 ring ring-(--ui-border)'
              },
              naked: {
                content: ''
              }
            },
            side: {
              left: {
                container: 'rtl:justify-end'
              },
              right: {
                container: 'ltr:justify-end ms-auto'
              }
            },
            leading: {
              true: ''
            },
            actions: {
              true: ''
            },
            compact: {
              true: {
                root: 'scroll-mt-3',
                container: 'gap-1.5 pb-3',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs'
              },
              false: {
                root: 'scroll-mt-4 sm:scroll-mt-6',
                container: 'gap-3 pb-8',
                leadingIcon: 'size-8',
                leadingAvatarSize: 'md'
              }
            }
          },
          compoundVariants: [
            {
              compact: true,
              actions: true,
              class: {
                container: 'pb-8'
              }
            },
            {
              leading: true,
              compact: false,
              side: 'left',
              class: {
                actions: 'left-11'
              }
            },
            {
              leading: true,
              compact: true,
              side: 'left',
              class: {
                actions: 'left-6.5'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: false,
              class: {
                content: 'px-4 py-3 rounded-[calc(var(--ui-radius)*2)] min-h-12',
                leading: 'mt-2'
              }
            },
            {
              variant: [
                'solid',
                'outline',
                'soft',
                'subtle'
              ],
              compact: true,
              class: {
                content: 'px-2 py-1 rounded-[calc(var(--ui-radius)*2)] min-h-8',
                leading: 'mt-1'
              }
            }
          ],
          defaultVariants: {
            variant: 'naked'
          }
        }
      }
    })
  ]
})