HextaUI

Marker: Sticky dates

With sticky, a marker stays at the top of its scroll area. Once it sticks, its lines fade and the label turns into a floating pill so it stays readable over messages. Put each day in its own section so the next date pushes the previous one away.

Kicking off the marker component today.
Shadcn's version is a good base. Let's add sticky dates.
Agreed, chats need them.
Sticky dates work. They turn into a pill when they stick.
Nice. Does it respect reduced motion?
Yes, the pill just appears.
Docs are up.
Shipping it.
🎉
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Marker, MarkerContent, MarkerTime } from "@/components/ui/marker"

const day = 24 * 60 * 60 * 1000

const days = [
  {
    date: new Date(Date.now() - 3 * day),
    messages: [
      "Kicking off the marker component today.",
      "Shadcn's version is a good base. Let's add sticky dates.",
      "Agreed, chats need them.",
    ],
  },
  {
    date: new Date(Date.now() - day),
    messages: [
      "Sticky dates work. They turn into a pill when they stick.",
      "Nice. Does it respect reduced motion?",
      "Yes, the pill just appears.",
    ],
  },
  {
    date: new Date(),
    messages: ["Docs are up.", "Shipping it.", "🎉"],
  },
]

export function MarkerSticky() {
  return (
    <div
      tabIndex={0}
      role="region"
      aria-label="Activity by day"
      className="h-80 w-full max-w-md overflow-y-auto overscroll-none rounded-xl border px-4 outline-none focus-visible:ring-3 focus-visible:ring-focus-ring focus-visible:outline-hidden"
    >
      {days.map((group) => (
        <section
          key={group.date.toDateString()}
          className="flex flex-col gap-3 py-3"
        >
          <Marker variant="separator" sticky>
            <MarkerContent>
              <MarkerTime date={group.date} />
            </MarkerContent>
          </Marker>
          {group.messages.map((message, index) => (
            <Bubble
              key={message}
              align={index % 2 === 0 ? "start" : "end"}
              variant={index % 2 === 0 ? "secondary" : "default"}
            >
              <BubbleContent>{message}</BubbleContent>
            </Bubble>
          ))}
        </section>
      ))}
    </div>
  )
}

This adds the example as components/examples/marker/sticky.tsx, together with the Marker component and the HextaUI theme tokens it needs.

pnpm dlx shadcn@latest add https://hextaui.com/r/marker-sticky.json

To add only the component, follow the Marker installation.

Props in this example

The Marker props this example sets, from the API reference.

PropTypeDefault
variant
"default" | "separator" | "border""default"
stickyStick to the top of the scroll area and become a pill while stuck.
booleanfalse
PropTypeDefault
dateRequired. Anything new Date() accepts.
Date | string | number–

Every prop is in the Marker API reference.

See them all, with keyboard support and accessibility notes, on the Marker page.