Isaiah

BJORK Message branch

Component

About

Message branch is a production-ready ai component from BJORK UI, packaged for shadcn registries.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds BJORK Message branch to your project and fits it to your theme.

Code

How BJORK Message branch is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";
import { ThemeProvider as BjorkDemoThemeProvider } from "next-themes";
import { useEffect, useRef, useState } from "react";
import { MessageBranch, SAMPLE_ASSISTANT_VERSIONS, SAMPLE_USER_VERSIONS, type MessageVersion } from "@/components/ui/bjork-message-branch";

const REWRITES = [
  "Your drafts now live on your device first. Lose the connection mid-sentence and Fieldnotes simply carries on, then syncs the moment you're back.",
  "New: offline drafts. Fieldnotes saves locally and syncs later, so a flaky connection never eats your work.",
  "Write without a signal. Fieldnotes keeps drafts on your device and syncs them when you reconnect.",
];

function Demo() {
  const [user, setUser] = useState<MessageVersion[]>(SAMPLE_USER_VERSIONS);
  const [assistant, setAssistant] = useState<MessageVersion[]>(SAMPLE_ASSISTANT_VERSIONS);
  const [writing, setWriting] = useState<{ id: string; text: string; shown: number } | null>(null);
  const timers = useRef<number[]>([]);
  const rewrites = useRef(0);
  useEffect(() => () => timers.current.forEach((t) => window.clearTimeout(t)), []);

  // Streams the pending rewrite into the newest assistant version, a few characters per tick.
  useEffect(() => {
    if (!writing) return;
    if (writing.shown >= writing.text.length) {
      const id = window.setTimeout(() => {
        setAssistant((list) => list.map((v) => (v.id === writing.id ? { ...v, streaming: false } : v)));
        setWriting(null);
      }, 0);
      return () => window.clearTimeout(id);
    }
    const id = window.setTimeout(() => {
      const shown = Math.min(writing.text.length, writing.shown + 4);
      setAssistant((list) =>
        list.map((v) => (v.id === writing.id ? { ...v, content: writing.text.slice(0, shown) } : v)),
      );
      setWriting({ ...writing, shown });
    }, 28);
    return () => window.clearTimeout(id);
  }, [writing]);

  // A real backend would start a request here. The demo adds an empty streaming version after a short wait.
  const startRewrite = () => {
    const n = ++rewrites.current;
    const t = window.setTimeout(() => {
      const id = `rewrite-${n}`;
      setAssistant((list) => [...list, { id, content: "", model: "Halcyon 3 Pro", createdAt: Date.now(), streaming: true }]);
      setWriting({ id, text: REWRITES[(n - 1) % REWRITES.length], shown: 0 });
    }, 900);
    timers.current.push(t);
  };

  return (
    <div className="flex w-[min(560px,calc(100vw-56px))] flex-col gap-5">
      <MessageBranch
        role="user"
        versions={user}
        onEdit={(content) => {
          setUser((list) => [...list, { id: `u${list.length + 1}`, content, createdAt: Date.now() }]);
          startRewrite();
        }}
      />
      <MessageBranch
        role="assistant"
        versions={assistant}
        defaultIndex={1}
        onRegenerate={startRewrite}
      />
    </div>
  );
}
function SourceDemo(){
const [session, setSession] = useState(0);
return <>

      <Demo key={session} />
    
</>;
}
export default function BjorkRegistryPreview(){return <BjorkDemoThemeProvider attribute="class" defaultTheme="dark" enableSystem={false} storageKey="bjork-review-demo-theme"><div data-component-demo className="dark flex min-h-screen w-full items-center justify-center bg-[var(--bjork-bg)] p-8 text-[var(--bjork-text)]"><div className="w-full max-w-[850px]"><SourceDemo/></div></div></BjorkDemoThemeProvider>}

Dependencies

More by Isaiah

View all
  • Agent Plan

    Agent Plan

    2.2K
  • Video Scroll Hero

    Video Scroll Hero

    1.4K
  • Voice Powered Orb

    Voice Powered Orb

    1.3K
  • Reveal Text

    Reveal Text

    1.1K
  • Leads Data Table

    Leads Data Table

    935
  • Portfolio Gallery

    Portfolio Gallery

    923
  • Message Dock

    Message Dock

    833
  • Ruler Carousel

    Ruler Carousel

    617