Components
IMessageThread
The ready-made container: token scope + a scrollbar-less scroll area (iMessage has none) + header/footer slots, with the footer riding above the mobile keyboard via useKeyboardInset. The three things every chat surface re-implements, bundled.
"use client";
import { useState } from "react";
import {
ChatBubble,
ChatHeader,
IMessageThread,
InputBar,
} from "imessage-ui";
import type { ChatHeaderBot } from "imessage-ui";
const BOTS: ChatHeaderBot[] = [
{ id: "riley", avatar: { initial: "R", gradient: ["#FF9FB2", "#E0506E"] } },
{ id: "devon", avatar: { initial: "D", gradient: ["#7B8FFF", "#5057E0"] } },
];
/** The whole phone: header slot + scrollable thread + footer slot. */
export default function ThreadDemo() {
const [draft, setDraft] = useState("");
const [sent, setSent] = useState<string[]>(["so it's just… the whole chat?"]);
return (
<IMessageThread
followKeyboard={false}
className="h-96 w-full max-w-sm overflow-hidden rounded-2xl"
header={<ChatHeader bots={BOTS} title="the group chat" embedded />}
footer={
<InputBar
embedded
value={draft}
onChange={setDraft}
onSend={text => {
setSent(prev => [...prev, text]);
setDraft("");
}}
/>
}
>
<div className="flex flex-col gap-1 px-3 py-2">
<ChatBubble variant="received" text="scroll area has no scrollbar, like the real thing" senderName="Riley" avatar={BOTS[0].avatar} />
{sent.map((text, i) => (
<ChatBubble key={i} variant="sent" text={text} isNewlySent={i === sent.length - 1 && i > 0} />
))}
</div>
</IMessageThread>
);
}Usage
import { IMessageThread, ChatHeader, InputBar } from "imessage-ui";
<IMessageThread
header={<ChatHeader bots={bots} embedded />}
footer={<InputBar embedded value={v} onChange={setV} onSend={send} />}>
{messages}
</IMessageThread>API reference
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | The message list. |
| header | ReactNode | — | Header slot — ChatHeader or LiquidGlassHeader. |
| footer | ReactNode | — | Footer slot — usually an embedded InputBar. |
| followKeyboard | boolean | true | Lift the footer above the on-screen keyboard (writes --kb-height on the root). |
| scrollRef | RefObject<HTMLDivElement | null> | — | Ref to the scroll area, for auto-scroll-to-bottom. |
| variant | "default" | "glass" | "default" | Same as IMessageScreen. |
| wallpaper | string | — | Chat wallpaper behind the messages. |
| className / style | string / CSSProperties | — | Passthrough to the root. |