Skip to content
zedkit
@zedtech/zedkit-ui

Follow a growing log to the latest

Follow the newest line until the reader scrolls up; a named button jumps back and resumes following.

alpha

At a glance

  • Who: Developers building a chat, log, or console that grows while the reader watches.
  • What: Follow the newest line until the reader scrolls up; a named button jumps back and resumes following. offset defaults to 8px; behavior defaults to "auto" (instant jump).
  • Use when: On any overflowing scroll parent (AppShell mainRef or a custom pane) with content that appends.
  • Avoid when: For route-change scroll-to-top — use Reset scroll on route change. CSS overflow-anchor cannot expose a latch for the button.
  • See also: Reset scroll on route change, Lay out an admin page (sidebar + topbar + header), Localize kit chrome in English or French

Install

pnpm add @zedtech/zedkit-ui

Latest: 2.0.1 (via changesets).

Example

Usage
"use client";
import { useRef, type ReactNode } from "react";
import { JumpToLatest, useStickToBottom } from "@zedtech/zedkit-ui";
export function LogPane({ children }: { children: ReactNode }) {
  const scroller = useRef<HTMLDivElement>(null);
  const { isStuck, jumpToLatest } = useStickToBottom(scroller);
  return (
    <div className="relative pane-shrink">
      <div ref={scroller} tabIndex={0} role="region" aria-label="Log" className="h-full overflow-y-auto focus-ring">
        {children}
      </div>
      <JumpToLatest className="absolute pin-bottom pin-x" stuck={isStuck} onClick={jumpToLatest} />
    </div>
  );
}

Wraps: (none)

Accessibility

Hidden while latched (not in the tab order). Visible control is a real button with the kit 44px phone target; empty label falls back to kit chrome (that visible text is the accessible name — do not pass a conflicting aria-label). jumpToLatest moves focus to the scroller. A custom pane needs tabIndex={0}, role="region", aria-label, and a visible focus ring (AppShell main already does this). Jumps instantly by default and always when motion is reduced (OS or html[data-motion=reduce]). behavior="smooth" while a log is still growing is a continuous animation — keep "auto" when the reader may be motion-sensitive. Not a live region: in chat, pair with StreamText; a plain log or console should add aria-live or role="status" if new lines must be announced.

On this page