Saurabh

Citations

AI chats

About

A collapsible list of source references paired with inline numbered citation markers, used to ground an AI/agent response in the sources it cites.

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

Code

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

Usage.tsx

"use client";

import {
  Citation,
  Citations,
  type CitationItem,
} from "@/components/ui/citations";
import { RotateCcw } from "lucide-react";
import { useReducedMotion } from "motion/react";
import { useEffect, useState } from "react";

const CITATION_ITEMS: CitationItem[] = [
  {
    id: "motion",
    title: "Motion documentation",
    domain: "motion.dev",
    url: "https://motion.dev/docs/react",
  },
  {
    id: "wai",
    title: "WAI accessibility patterns",
    domain: "w3.org",
    url: "https://www.w3.org/WAI/ARIA/apg/",
  },
  {
    id: "react",
    title: "React documentation",
    domain: "react.dev",
    url: "https://react.dev/learn",
  },
];

function CitationsDemo() {
  const reduce = useReducedMotion() ?? false;
  const [visible, setVisible] = useState(reduce ? CITATION_ITEMS.length : 0);

  useEffect(() => {
    if (reduce) return;
    const timers = CITATION_ITEMS.map((_, index) =>
      window.setTimeout(() => setVisible(index + 1), 500 + index * 700),
    );
    return () => timers.forEach(window.clearTimeout);
  }, [reduce]);

  return (
    <div className="space-y-4">
      <p className="text-sm leading-6 text-foreground/90">
        Use layout-aware motion for newly appended results{" "}
        <Citation citationId="motion" index={1} idPrefix="preview-source" /> and
        preserve accessible disclosure behavior{" "}
        <Citation citationId="wai" index={2} idPrefix="preview-source" /> as the
        list grows.
      </p>
      <Citations
        idPrefix="preview-source"
        citations={CITATION_ITEMS.slice(0, visible)}
        defaultOpen
      />
    </div>
  );
}

export default function CitationsPreview() {
  const [run, setRun] = useState(0);

  return (
    <div className="relative h-[410px] w-full max-w-lg">
      <CitationsDemo key={run} />
      <button
        type="button"
        onClick={() => setRun((value) => value + 1)}
        className="absolute bottom-0 left-0 inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs font-medium text-muted-foreground outline-none transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
      >
        <RotateCcw className="size-3" />
        Replay
      </button>
    </div>
  );
}

Dependencies

More by Saurabh

View all
  • BeUI Tilt Card

    BeUI Tilt Card

    373
  • BeUI Expandable Tabs

    BeUI Expandable Tabs

    347
  • BeUI File Upload

    BeUI File Upload

    293
  • BeUI Bouncy Accordion

    BeUI Bouncy Accordion

    204
  • BeUI Create Menu

    BeUI Create Menu

    199
  • BeUI Expanable Action Bar

    BeUI Expanable Action Bar

    190
  • Animated Sidebar

    Animated Sidebar

    184
  • Loader

    Loader

    181

More in AI chats

View all
  • AI Actions

    AI Actions

    324
  • AI Task List

    AI Task List

    161
  • Message Thread

    Message Thread

    41
  • Color Picker

    Color Picker

    94
  • Agent Chat

    Agent Chat

    18
  • Chat Bubble

    Chat Bubble

    185
  • System Message

    System Message

    56
  • Code Block

    Code Block

    12

Explore more

Part of beUi — browse the full library on 21st.dev.