Skip to content
Sign in
ConversationConversation dividerMenu

Conversation divider

Dividers inside a thread: day boundaries (Today, Yesterday, Mon 12 Oct), where unread messages start, context events such as a model change or a compaction, and the point where the user left off. A hairline with a short label, centered or start aligned, with sticky dates.

A day boundary, a model change, a compaction and where unread replies start.

Installation

$ pnpm dlx shadcn@latest add https://chatcn.dev/r/conversation-divider.json

Usage

tsx
import {
  ConversationDivider,
  ConversationDividerAction,
} from "@/components/ui/chatcn/conversation-divider"

<ConversationDivider variant="date" date={message.createdAt} sticky />
<ConversationDivider variant="unread" count={3} />
<ConversationDivider icon={<ContextWindowIcon />} action={<ConversationDividerAction>View summary</ConversationDividerAction>}>
  Context compacted, 48k tokens saved
</ConversationDivider>
<ConversationDivider variant="resume" />

Dates format relative to now: Today, Yesterday, then the weekday, day and month, with the year only when it differs. Commas from the locale are dropped so the label stays calm. formatDividerDate is exported for use elsewhere, such as a thread list.

Unread uses the blue info tone on the rule, the label and a 6 px dot, and the words carry the meaning on their own. Resume uses a dashed rule. Events stay neutral.

Examples

Divider kinds

Date, unread, event and resume dividers, centered and start aligned.

Sticky dates

With sticky, a date divider pins to the top of the scrolling thread while its day scrolls by. While pinned, the rules fade out and the label sits on a small card surface so it stays readable over messages.

Each day's label pins to the top while its messages scroll by, and gains a small surface while pinned.

Long labels and RTL

Long labels truncate to one line and large counts keep their separators.

Props

PropTypeNotes
variant"date" | "unread" | "event" | "resume"Defaults to event
childrenReactNodeThe label. Overrides the derived text
dateDate | number | stringFor date
nowDate | numberReference for Today and Yesterday. Defaults to the current time
localestringDate locale. Defaults to the browser's
countnumberFor unread: "3 new messages"
iconReactNodeA 14 px icon before the label
actionReactNodeUsually a ConversationDividerAction
metaReactNodeTrailing detail such as a time, in tabular figures
align"center" | "start"Defaults to center
stickybooleanPin to the top of the scroll container
stickyOffsetnumberPx from the top while pinned. Defaults to 8

Accessibility

  • Date labels are level 3 headings, so screen reader users can jump between days.
  • The rules are decorative and hidden. Labels are plain text in reading order, never color alone.
  • Actions are real buttons with a 44 px hit area on touch screens.

Motion

  • Only the sticky label moves between states: its surface and the rules cross over in 150 ms when it pins or unpins. Under reduced motion that stays a short fade.