EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
Chat·component·@astryxdesign/core

Chat Message Metadata

Composable metadata row for chat messages. Renders timestamp, footer content, and delivery status in a single row. Direction reverses for user sender. Omits the row when both slots are omitted or non-rendering scalars and status is omitted.

Open in Playground @astryxdesign/core/Chat

Showcases and examples

4 documented examples

Chat Message Metadata

Three-message conversation showcasing error status with retry, delivery status, and full footer actions with model label.

Preview loads on approachPreview loads on approach
Exact source · chat-message-metadata-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {
  ChatMessageList,
  ChatMessage,
  ChatMessageBubble,
  ChatMessageMetadata,
} from '@astryxdesign/core/Chat';
import {Timestamp} from '@astryxdesign/core/Timestamp';
import {Text} from '@astryxdesign/core/Text';
import {Button} from '@astryxdesign/core/Button';
import {Icon} from '@astryxdesign/core/Icon';
import {HStack, VStack} from '@astryxdesign/core/Layout';
import {
  ClipboardDocumentIcon,
  ArrowPathIcon,
  HandThumbUpIcon,
  HandThumbDownIcon,
} from '@heroicons/react/24/outline';

export default function ChatMessageMetadataShowcase() {
  return (
    <VStack style={{maxWidth: 600}}>
      <ChatMessageList>
        <ChatMessage sender="assistant">
          <ChatMessageBubble
            metadata={
              <ChatMessageMetadata
                timestamp={
                  <Timestamp value="2026-03-15T14:30:00" format="time" />
                }
                status="error"
                footer={
                  <HStack gap={1}>
                    <Button
                      label="Retry"
                      variant="ghost"
                      size="sm"
                      icon={<Icon icon={ArrowPathIcon} size="sm" />}
                      isIconOnly
                      onClick={() => {}}
                    />
                  </HStack>
                }
              />
            }>
            Sorry, something went wrong on my end.
          </ChatMessageBubble>
        </ChatMessage>

        <ChatMessage sender="user">
          <ChatMessageBubble
            metadata={
              <ChatMessageMetadata
                timestamp={
                  <Timestamp value="2026-03-15T14:31:00" format="time" />
                }
                status="read"
              />
            }>
            No worries — try again with just the last 24 hours of logs.
          </ChatMessageBubble>
        </ChatMessage>

        <ChatMessage sender="assistant">
          <ChatMessageBubble
            metadata={
              <ChatMessageMetadata
                timestamp={
                  <Timestamp value="2026-03-15T14:32:00" format="time" />
                }
                footer={
                  <HStack gap={1}>
                    <Button
                      label="Copy"
                      variant="ghost"
                      size="sm"
                      icon={<Icon icon={ClipboardDocumentIcon} size="sm" />}
                      isIconOnly
                      onClick={() => {}}
                    />
                    <Button
                      label="Retry"
                      variant="ghost"
                      size="sm"
                      icon={<Icon icon={ArrowPathIcon} size="sm" />}
                      isIconOnly
                      onClick={() => {}}
                    />
                    <Button
                      label="Good response"
                      variant="ghost"
                      size="sm"
                      icon={<Icon icon={HandThumbUpIcon} size="sm" />}
                      isIconOnly
                      onClick={() => {}}
                    />
                    <Button
                      label="Bad response"
                      variant="ghost"
                      size="sm"
                      icon={<Icon icon={HandThumbDownIcon} size="sm" />}
                      isIconOnly
                      onClick={() => {}}
                    />
                    <Text type="supporting" color="secondary">
                      Claude Opus 4.6
                    </Text>
                  </HStack>
                }
              />
            }>
            The canary at 11:42 AM caused a memory spike. Rolled back at 11:58
            AM.
          </ChatMessageBubble>
        </ChatMessage>
      </ChatMessageList>
    </VStack>
  );
}

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 React content remains caller-owned.

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

Typed props

PropType and behavior
timestampReactNode
Timestamp content: a string or Timestamp component.
Slot: Text
footerReactNode
Footer content: model info, reaction buttons, copy button.
Slot: Text
status'sending' | 'sent' | 'delivered' | 'read' | 'error'
Message delivery status. Shows icon + label.

Anatomy

Metadata row · required

Sender-aware line containing the visible metadata items.

Timestamp · optional

Caller-supplied time content at the start of the logical sequence.

Footer · optional

Caller-supplied information or actions between time and status.

Status · optional

Localized delivery icon and text when a status is supplied.