ChatMessage

One message on the chat page: the client's words in a soft gray bubble on the right, Okami's answer as bare text on the left.

Playground

Any chance Saturday morning?
Message
State

A conversation

The client's words sit in a bubble of the card tint, its corner tucked toward them; Okami speaks on the atmosphere itself, never in a box. While a reply is on its way, the TypingIndicator takes Okami's side; quick replies follow as Chips.

Any chance Saturday morning?
Hey Marek! Saturday I've got 9:30 or 11:00 for a skin fade — which works?
11 👌

With an author

When someone other than Okami answers on its side — the studio stepping into a conversation from the Inbox — their name sits above the words, small and soft, so the client knows a person wrote it.

Can I bring my dog?

Belaze

Of course, she's welcome!

Failed

When a message doesn't reach Okami it stays in the thread, saying so beneath, with a ghost Button to send the same words again. Nothing is lost and nothing needs retyping.

Is Friday 10:00 still free?

Message not delivered.

With a file

A file sent with a message — an owner's photo of their price list — shows by name with a paperclip, above any words. The file itself never shows: the bubble says what was sent. On Instagram, where Okami keeps no media, it says what kind it was by its own glyph and opens the chat in Instagram, where the photo or voice note is.

cennik.jpgHere's our price list.
price-list-2026.pdf

Long messages

A message takes at most five sixths of the thread, wraps, and keeps the line breaks its sender typed.

Hi, how long does balayage take? And do you have anything Friday? I can do mornings only.
About three hours with Nina. Friday she's free at 9:00 — shall I book you in?

API reference

PropTypeDefaultDescription
from"client" | "agent"—Who wrote it: the client, in a soft gray bubble on the right (ink at 5%, no edge or shadow); or Okami, as bare text on the left.
childrenReactNode—The message. Line breaks are kept.
authorstring—Who wrote it, small above the words: the studio's name when a member answers on Okami's side.
attachmentstring—A file sent with the message, by name, or what was sent ("Voice message"), above the words. With it, children may be left out.
attachmentIconIconPaperclipThe attachment's glyph: Image, Mic, Video and the like.
attachmentHrefstring—Where the attachment is, opened in a new tab: the Instagram chat (ig.me/m/<username>).
failedbooleanfalseIt didn't reach Okami. Shows failedLabel and the retry beneath when onRetry is set.
onRetry() => void—Sends the same message again.
failedLabelstring—What went wrong, e.g. "Message not delivered."
retryLabelstring—The retry action, e.g. "Try again".
classNamestring—Layout only, on the row.

Guidelines

  • Only the client's words sit in a bubble. Okami answers as bare text on the atmosphere — the agent is the place, not a participant in a box.
  • Messages rise in once, as they land, and never move again. Under prefers-reduced-motion they simply appear.
  • A failed message keeps its place and its words; the retry sends them again as they were. Never drop it silently.
  • Show messages whole — no truncation, no "read more". Keep the agent's replies short enough not to need it.