# Chat Message Metadata

## Usage

Place ChatMessageMetadata below a message or in the last ChatMessageBubble metadata slot to show a timestamp, footer content, and optional delivery status. Non-rendering scalar slots (booleans and empty strings) create no separator; numeric zero remains visible. Composite slot content remains caller-owned.

The row renders nothing at all when `timestamp`, `footer`, and `status` are all absent. The dots between the three parts only appear next to a part that is actually there, so a two-part row reads `2:30 PM · Read` and a three-part row reads `2:30 PM · GPT-4o · Read`.

```vue
<script setup lang="ts">
import { ChatMessageMetadata } from '@astryx-vue/core/Chat'
</script>

<template>
  <ChatMessageMetadata status="read" timestamp="2:30 PM" />
</template>
```

### Anatomy

- **Metadata row**: Sender-aware line containing the visible metadata items.
- **Timestamp**: Caller-supplied time content at the start of the logical sequence.
- **Footer**: Caller-supplied information or actions between time and status.
- **Status**: Localized delivery icon and text when a status is supplied.

## Best practices

| Guidance | Practices |
| --- | --- |
| Do | Put metadata in the last bubble metadata slot when the message uses bubbles, so it follows the bubble content. |
| Do | Pass timestamp and footer content independently; separators are omitted for non-rendering scalar slots. Composite slot content is used as supplied. |
| Don't | Do not supply footer actions without their own accessible names and interaction behavior; the metadata row does not own those controls. |
| Don't | Do not put the same metadata on both a bubble and its enclosing message. |

## Examples

Common configurations, variations, and states.

### Footer Actions

Assistant message with footer actions: copy, retry, thumbs up/down, and model label. Use for AI responses that need feedback or utility controls.

```vue
<script setup lang="ts">
import { ChatMessage, ChatMessageBubble, ChatMessageList, ChatMessageMetadata } from '@astryx-vue/core/Chat'
import { IconButton } from '@astryx-vue/core/IconButton'
</script>

<template>
  <ChatMessageList>
    <ChatMessage sender="user">
      <ChatMessageBubble>
        {{ 'Summarize the Q1 revenue report.' }}
        <template #metadata>
          <ChatMessageMetadata status="read" timestamp="9:41 AM" />
        </template>
      </ChatMessageBubble>
    </ChatMessage>
    <ChatMessage sender="assistant">
      <ChatMessageBubble variant="ghost">
        {{ 'Q1 revenue reached $2.4B, up 18% year-over-year. Enterprise subscriptions drove 62% of the growth, while ad revenue held steady at $890M.' }}
        <template #metadata>
          <ChatMessageMetadata timestamp="9:42 AM">
            <template #footer>
              <span class="chat-preview__actions">
                <IconButton label="Copy" variant="ghost" size="sm">
                  <span class="i-carbon-copy" />
                </IconButton>
                <IconButton label="Retry" variant="ghost" size="sm">
                  <span class="i-carbon-renew" />
                </IconButton>
                <IconButton label="Thumbs up" variant="ghost" size="sm">
                  <span class="i-carbon-thumbs-up" />
                </IconButton>
                <IconButton label="Thumbs down" variant="ghost" size="sm">
                  <span class="i-carbon-thumbs-down" />
                </IconButton>
                <span>GPT-4o</span>
              </span>
            </template>
          </ChatMessageMetadata>
        </template>
      </ChatMessageBubble>
    </ChatMessage>
  </ChatMessageList>
</template>
```

### Status

All 5 delivery statuses (sending, sent, delivered, read, and error), each with a timestamp. Use to show message delivery progress or surface failures.

```vue
<script setup lang="ts">
import type { ChatMessageStatus } from '@astryx-vue/core/Chat'
import { ChatMessage, ChatMessageBubble, ChatMessageList, ChatMessageMetadata } from '@astryx-vue/core/Chat'

const rows: { status: ChatMessageStatus, text: string }[] = [
  { status: 'sending', text: 'Deploying the update now…' },
  { status: 'sent', text: 'Config pushed to staging.' },
  { status: 'delivered', text: 'Verified on the staging cluster.' },
  { status: 'read', text: 'Looks good — promoting to prod.' },
  { status: 'error', text: 'Rollback triggered, checking logs.' },
]
</script>

<template>
  <ChatMessageList>
    <ChatMessage v-for="row in rows" :key="row.status" sender="user">
      <ChatMessageBubble>
        {{ row.text }}
        <template #metadata>
          <ChatMessageMetadata :status="row.status" timestamp="10:15 AM" />
        </template>
      </ChatMessageBubble>
    </ChatMessage>
  </ChatMessageList>
</template>
```

### Timestamps

Timestamp-only metadata on user and assistant messages. Supports absolute time and relative formats via Timestamp.

```vue
<script setup lang="ts">
import { ChatMessage, ChatMessageBubble, ChatMessageList, ChatMessageMetadata } from '@astryx-vue/core/Chat'
</script>

<template>
  <ChatMessageList>
    <ChatMessage sender="user">
      <ChatMessageBubble>
        {{ 'Thanks — any blockers I should know about?' }}
        <template #metadata>
          <ChatMessageMetadata timestamp="2:30 PM" />
        </template>
      </ChatMessageBubble>
    </ChatMessage>
    <ChatMessage sender="assistant">
      <ChatMessageBubble variant="ghost">
        {{ 'Relative timestamps work too — helpful for older messages where the exact time matters less than recency.' }}
        <template #metadata>
          <ChatMessageMetadata timestamp="5 months ago" />
        </template>
      </ChatMessageBubble>
    </ChatMessage>
  </ChatMessageList>
</template>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `timestamp` | `string` | — | Time or other short text, at the start of the row. |
| `footer` | `string` | — | Secondary text between the timestamp and the status, such as a model name. |
| `status` | `'sending' \| 'sent' \| 'delivered' \| 'read' \| 'error'` | — | Delivery state. Renders a localized icon and label. The row renders nothing when `timestamp`, `footer`, and `status` are all absent. |

## Slots

- `timestamp`: replaces the `timestamp` prop. Use it to put a `Timestamp` component in place of plain text.
- `footer`: replaces the `footer` prop. Use it for buttons such as copy, retry, and reactions; each control needs its own accessible name.
