Thinking Indicator
fluid-functionalism/thinking-indicatorFreeComponent
Animated loading indicator with morphing SVG path (circle to infinity loop) and shimmer text rotation. Cycles through customizable status words.
Install it
npx shadcn@latest add https://fluidfunctionalism.com/r/thinking-indicator.jsonSource
1"use client";23import { forwardRef, useState, useEffect, type HTMLAttributes } from "react";4import { motion, AnimatePresence, useReducedMotion } from "framer-motion";5import { cn } from "@/lib/utils";6import { fontWeights } from "@/lib/font-weight";78const circleA =9 "M 12 8 C 14.21 8 16 9.79 16 12 C 16 14.21 14.21 16 12 16 C 9.79 16 8 14.21 8 12 C 8 9.79 9.79 8 12 8 Z";1011const infinity =12 "M 12 12 C 14 8.5 19 8.5 19 12 C 19 15.5 14 15.5 12 12 C 10 8.5 5 8.5 5 12 C 5 15.5 10 15.5 12 12 Z";1314const circleB =15 "M 12 16 C 14.21 16 16 14.21 16 12 C 16 9.79 14.21 8 12 8 C 9.79 8 8 9.79 8 12 C 8 14.21 9.79 16 12 16 Z";1617const words = ["Thinking", "Moonwalking", "Planning", "Refining"];1819interface ThinkingIndicatorProps extends HTMLAttributes<HTMLDivElement> {20 /** Show the morphing circle⇄infinity glyph before the label. Set to `false`21 * for a text-only indicator (e.g. inline before a streamed reply). */22 showIcon?: boolean;23}2425const ThinkingIndicator = forwardRef<HTMLDivElement, ThinkingIndicatorProps>(26 ({ className, showIcon = true, ...props }, ref) => {27 const [index, setIndex] = useState(0);28 // Reduced motion drops the infinite glyph morph and the word cycling — a29 // static glyph and label carry the same meaning without the movement.30 const reduceMotion = useReducedMotion() ?? false;3132 useEffect(() => {33 if (reduceMotion) return;34 const interval = setInterval(() => {35 setIndex((i) => (i + 1) % words.length);36 }, 4000);37 return () => clearInterval(interval);38 }, [reduceMotion]);3940 return (41 <div42 ref={ref}43 role="status"44 className={cn("flex items-center gap-2 px-3 py-2", className)}45 {...props}46 >47 {/* Static announcement — the cycling word display below is aria-hidden48 so screen readers hear one "Thinking…" instead of a re-announcement49 every 4 seconds. */}50 <span className="sr-only">Thinking…</span>51 {showIcon && (52 <motion.svg53 aria-hidden54 width={20}55 height={20}56 viewBox="0 0 24 24"57 fill="none"58 stroke="currentColor"59 strokeWidth={1.5}60 strokeLinecap="round"61 strokeLinejoin="round"62 className="text-muted-foreground shrink-0"63 >64 {reduceMotion ? (65 <path d={infinity} />66 ) : (67 <motion.path68 animate={{69 d: [circleA, infinity, circleB, infinity, circleA],70 }}71// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from fluid-functionalism
All 53 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | fluid-functionalism | Components | Free | 3 deps | |
| Accordion (Base UI)accordion-base | fluid-functionalism | Components | Free | 3 deps | |
| Ask User Questionsask-user-questions | fluid-functionalism | Components | Free | 2 deps | |
| Badgebadge | fluid-functionalism | Components | Free | 1 dep | |
| Buttonbutton | fluid-functionalism | Components | Free | 4 deps | |
| Button (Base UI)button-base | fluid-functionalism | Components | Free | 4 deps | |
| Cardcard | fluid-functionalism | Components | Free | 1 dep | |
| Chat Messagechat-message | fluid-functionalism | Components | Free | 1 dep |
