Message

A single row in a conversation. The two sides are deliberately asymmetric: the user's words are an embossed key they placed on the surface; the assistant's reply is flat prose — the surface itself speaking.

How do springs differ from durations in seamui?
SU
Springs are physics-based — they react to velocity, so a press settles naturally instead of running a fixed clock. Durations are reserved for opacity fades and layout dimensions that can't spring cleanly.
tsx
import {
  Message,
  MessageAvatar,
  MessageContent,
} from "@/registry/seam/ui/message"

export default function MessageDemo() {
  return (
    <div className="flex w-full max-w-md flex-col gap-2">
      <Message from="user">
        <MessageContent>
          How do springs differ from durations in seamui?
        </MessageContent>
      </Message>
      <Message from="assistant">
        <MessageAvatar name="Seam UI" />
        <MessageContent>
          Springs are physics-based — they react to velocity, so a press settles
          naturally instead of running a fixed clock. Durations are reserved for
          opacity fades and layout dimensions that can&apos;t spring cleanly.
        </MessageContent>
      </Message>
    </div>
  )
}
bunx --bun @seamui/cli@latest add message

Notes

  • Each row rises off the canvas on springs.snappy as it enters; under reduced motion it fades in place and the actions appear instantly.
  • Actions reveal with an opacity-only transition on hover and :focus-within, so keyboard users can reach them. Each action button requires an aria-label.
  • MessageAvatar dogfoods Avatar with an initials fallback derived from name.
  • The live region that announces streamed messages lives on Conversation, not here, to avoid double-announcing.

Press feedback, reduced motion, and haptics follow the global policy — see Motion and Haptics.