Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions apps/www/config/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,12 @@ export const docsConfig: DocsConfig = {
items: [],
label: "",
},
{
title: "Infinity Text",
href: `/docs/components/infinity-text`,
items: [],
label: "",
},
],
},
],
Expand Down
67 changes: 67 additions & 0 deletions apps/www/content/docs/components/infinity-text.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
---
title: Infinity Text
date: 2025-11-25
description: A smooth, infinitely scrolling marquee text component, fully customizable using Tailwind CSS.
author: aniketsaha
published: true
---

<ComponentPreview name="infinity-text-demo" />

## Installation

<Tabs defaultValue="cli">

<TabsList>
<TabsTrigger value="cli">CLI</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">

```bash
npx shadcn@latest add @magicui/infinity-text
```

</TabsContent>

<TabsContent value="manual">

<Steps>

<Step>Copy and paste the following code into your project.</Step>

<ComponentSource name="infinity-text" />

<Step>Update the import paths to match your project setup.</Step>

</Steps>

</TabsContent>

</Tabs>

## Usage

```tsx showLineNumbers
import { InfinityText } from "@/components/ui/infinity-text"
```

```tsx showLineNumbers
<InfinityText text="Recent Works" />
```

## Props

| Prop | Type | Default | Description |
| ----------- | ----------------------- | ------------- | ----------------------------------------------------- |
| `text` | `string` | `RECENT WORK` | The color of the component |
| `speed` | `number` | `50` | Controls how fast the text scrolls |
| `fontSize` | `string` | `text-6xl` | Tailwind font-size class applied to the text |
| `fontStyle` | `string` | `-` | Custom font class (Google Fonts, Tailwind, or custom) |
| `separator` | `string` | `•` | Separator placed between repeated text segments |
| `className` | `string` | `-` | Additional CSS classes for the container |
| `colorMode` | `auto \| light \| dark` | `auto` | Automatically switches text color based on background |

## Credits

- Credit to [@AniketSaha](https://github.com/Aniket-a14)
124 changes: 124 additions & 0 deletions apps/www/public/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8337,6 +8337,130 @@ export default function IconCloudDemo() {



===== COMPONENT: infinity-text =====
Title: Infinity Text
Description: A component with an infinitely scrolling text.

--- file: magicui/infinity-text.tsx ---
"use client"

import { useEffect, useRef, useState } from "react"
import { motion } from "framer-motion"

import { cn } from "@/lib/utils"

interface InfinityTextProps {
text?: string
speed?: number
fontSize?: string
fontStyle?: string
separator?: string
className?: string
colorMode?: "auto" | "light" | "dark" // NEW
}

export function InfinityText({
text = "RECENT WORK",
speed = 50,
fontSize = "text-6xl",
fontStyle = "",
separator = "•",
className,
colorMode = "auto",
}: InfinityTextProps) {
const containerRef = useRef<HTMLDivElement | null>(null)
const textRef = useRef<HTMLSpanElement | null>(null)

const [textWidth, setTextWidth] = useState(0)
const [textColor, setTextColor] = useState("white")

// Measure width
useEffect(() => {
const measure = () => {
if (textRef.current) {
setTextWidth(textRef.current.offsetWidth)
}
}

measure()
window.addEventListener("resize", measure)
return () => window.removeEventListener("resize", measure)
}, [])

// Detect background + pick correct color
useEffect(() => {
if (colorMode === "light") {
setTextColor("black")
return
}
if (colorMode === "dark") {
setTextColor("white")
return
}

if (containerRef.current) {
const bg = getComputedStyle(containerRef.current).backgroundColor

const match = bg.match(/\d+/g)
if (!match) return

const [r, g, b] = match.map(Number)
const brightness = (r * 299 + g * 587 + b * 114) / 1000

if (brightness > 150) {
setTextColor("black")
} else {
setTextColor("white")
}
}
}, [colorMode])

const scrollingText = ` ${text} ${separator} `
const duration = textWidth ? textWidth / speed : 10

return (
<div
ref={containerRef}
className={cn(
"relative w-full overflow-hidden p-4 select-none",
className
)}
>
<motion.div
className={cn("flex font-bold whitespace-nowrap", fontSize, fontStyle)}
style={{ color: textColor }}
initial={{ x: 0 }}
animate={{ x: -textWidth }}
transition={{
repeat: Infinity,
repeatType: "loop",
duration,
ease: "linear",
}}
>
<span ref={textRef}>{scrollingText.repeat(60)}</span>
</motion.div>
</div>
)
}


===== EXAMPLE: infinity-text-demo =====
Title: Infinity Text Demo

--- file: example/infinity-text-demo.tsx ---
import { InfinityText } from "../magicui/infinity-text"

export default function InfinityTextDemo() {
return (
<div>
<InfinityText text="Recent Works" />
</div>
)
}



===== COMPONENT: interactive-grid-pattern =====
Title: Interactive Grid Pattern
Description: A interactive background grid pattern made with SVGs, fully customizable using Tailwind CSS.
Expand Down
2 changes: 2 additions & 0 deletions apps/www/public/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ This file provides LLM-friendly entry points to documentation and examples.
- [Highlighter](https://magicui.design/docs/components/highlighter): A text highlighter that mimics the effect of a human-drawn marker stroke.
- [Hyper Text](https://magicui.design/docs/components/hyper-text): A text animation that scrambles letters before revealing the final text.
- [Icon Cloud](https://magicui.design/docs/components/icon-cloud): An interactive 3D tag cloud component
- [Infinity Text](https://magicui.design/docs/components/infinity-text): A component with an infinitely scrolling text.
- [Interactive Grid Pattern](https://magicui.design/docs/components/interactive-grid-pattern): A interactive background grid pattern made with SVGs, fully customizable using Tailwind CSS.
- [interactive-hover-button](https://magicui.design/docs/components/interactive-hover-button): The interactive-hover-button component.
- [iPhone](https://magicui.design/docs/components/iphone): A mockup of the iPhone
Expand Down Expand Up @@ -214,6 +215,7 @@ This file provides LLM-friendly entry points to documentation and examples.
- [light-rays-demo](https://github.com/magicuidesign/magicui/blob/main/example/light-rays-demo.tsx): Example usage
- [Dotted Map Demo](https://github.com/magicuidesign/magicui/blob/main/example/dotted-map-demo.tsx): Example usage
- [Dotted Map Demo 2](https://github.com/magicuidesign/magicui/blob/main/example/dotted-map-demo-2.tsx): Example usage
- [Infinity Text Demo](https://github.com/magicuidesign/magicui/blob/main/example/infinity-text-demo.tsx): Example usage

## Optional

Expand Down
17 changes: 17 additions & 0 deletions apps/www/public/r/infinity-text-demo.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "infinity-text-demo",
"type": "registry:example",
"title": "Infinity Text Demo",
"description": "Example showing an infinitely scrolling text.",
"registryDependencies": [
"@magicui/infinity-text"
],
"files": [
{
"path": "registry/example/infinity-text-demo.tsx",
"content": "import { InfinityText } from \"../magicui/infinity-text\"\n\nexport default function InfinityTextDemo() {\n return (\n <div>\n <InfinityText text=\"Recent Works\" />\n </div>\n )\n}\n",
"type": "registry:example"
}
]
}
17 changes: 17 additions & 0 deletions apps/www/public/r/infinity-text.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "infinity-text",
"type": "registry:ui",
"title": "Infinity Text",
"description": "A component with an infinitely scrolling text.",
"dependencies": [
"framer-motion"
],
"files": [
{
"path": "registry/magicui/infinity-text.tsx",
"content": "\"use client\"\n\nimport { useEffect, useRef, useState } from \"react\"\nimport { motion } from \"framer-motion\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface InfinityTextProps {\n text?: string\n speed?: number\n fontSize?: string\n fontStyle?: string\n separator?: string\n className?: string\n colorMode?: \"auto\" | \"light\" | \"dark\" // NEW\n}\n\nexport function InfinityText({\n text = \"RECENT WORK\",\n speed = 50,\n fontSize = \"text-6xl\",\n fontStyle = \"\",\n separator = \"•\",\n className,\n colorMode = \"auto\",\n}: InfinityTextProps) {\n const containerRef = useRef<HTMLDivElement | null>(null)\n const textRef = useRef<HTMLSpanElement | null>(null)\n\n const [textWidth, setTextWidth] = useState(0)\n const [textColor, setTextColor] = useState(\"white\")\n\n // Measure width\n useEffect(() => {\n const measure = () => {\n if (textRef.current) {\n setTextWidth(textRef.current.offsetWidth)\n }\n }\n\n measure()\n window.addEventListener(\"resize\", measure)\n return () => window.removeEventListener(\"resize\", measure)\n }, [])\n\n // Detect background + pick correct color\n useEffect(() => {\n if (colorMode === \"light\") {\n setTextColor(\"black\")\n return\n }\n if (colorMode === \"dark\") {\n setTextColor(\"white\")\n return\n }\n\n if (containerRef.current) {\n const bg = getComputedStyle(containerRef.current).backgroundColor\n\n const match = bg.match(/\\d+/g)\n if (!match) return\n\n const [r, g, b] = match.map(Number)\n const brightness = (r * 299 + g * 587 + b * 114) / 1000\n\n if (brightness > 150) {\n setTextColor(\"black\")\n } else {\n setTextColor(\"white\")\n }\n }\n }, [colorMode])\n\n const scrollingText = ` ${text} ${separator} `\n const duration = textWidth ? textWidth / speed : 10\n\n return (\n <div\n ref={containerRef}\n className={cn(\n \"relative w-full overflow-hidden p-4 select-none\",\n className\n )}\n >\n <motion.div\n className={cn(\"flex font-bold whitespace-nowrap\", fontSize, fontStyle)}\n style={{ color: textColor }}\n initial={{ x: 0 }}\n animate={{ x: -textWidth }}\n transition={{\n repeat: Infinity,\n repeatType: \"loop\",\n duration,\n ease: \"linear\",\n }}\n >\n <span ref={textRef}>{scrollingText.repeat(60)}</span>\n </motion.div>\n </div>\n )\n}\n",
"type": "registry:ui"
}
]
}
30 changes: 30 additions & 0 deletions apps/www/public/r/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,21 @@
}
]
},
{
"name": "infinity-text",
"type": "registry:ui",
"title": "Infinity Text",
"description": "A component with an infinitely scrolling text.",
"dependencies": [
"framer-motion"
],
"files": [
{
"path": "registry/magicui/infinity-text.tsx",
"type": "registry:ui"
}
]
},
{
"name": "magic-card-demo",
"type": "registry:example",
Expand Down Expand Up @@ -3351,6 +3366,21 @@
}
]
},
{
"name": "infinity-text-demo",
"type": "registry:example",
"title": "Infinity Text Demo",
"description": "Example showing an infinitely scrolling text.",
"registryDependencies": [
"@magicui/infinity-text"
],
"files": [
{
"path": "registry/example/infinity-text-demo.tsx",
"type": "registry:example"
}
]
},
{
"name": "utils",
"type": "registry:lib",
Expand Down
30 changes: 30 additions & 0 deletions apps/www/public/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,21 @@
}
]
},
{
"name": "infinity-text",
"type": "registry:ui",
"title": "Infinity Text",
"description": "A component with an infinitely scrolling text.",
"dependencies": [
"framer-motion"
],
"files": [
{
"path": "registry/magicui/infinity-text.tsx",
"type": "registry:ui"
}
]
},
{
"name": "magic-card-demo",
"type": "registry:example",
Expand Down Expand Up @@ -3351,6 +3366,21 @@
}
]
},
{
"name": "infinity-text-demo",
"type": "registry:example",
"title": "Infinity Text Demo",
"description": "Example showing an infinitely scrolling text.",
"registryDependencies": [
"@magicui/infinity-text"
],
"files": [
{
"path": "registry/example/infinity-text-demo.tsx",
"type": "registry:example"
}
]
},
{
"name": "utils",
"type": "registry:lib",
Expand Down
30 changes: 30 additions & 0 deletions apps/www/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,21 @@
}
]
},
{
"name": "infinity-text",
"type": "registry:ui",
"title": "Infinity Text",
"description": "A component with an infinitely scrolling text.",
"dependencies": [
"framer-motion"
],
"files": [
{
"path": "registry/magicui/infinity-text.tsx",
"type": "registry:ui"
}
]
},
{
"name": "magic-card-demo",
"type": "registry:example",
Expand Down Expand Up @@ -3351,6 +3366,21 @@
}
]
},
{
"name": "infinity-text-demo",
"type": "registry:example",
"title": "Infinity Text Demo",
"description": "Example showing an infinitely scrolling text.",
"registryDependencies": [
"@magicui/infinity-text"
],
"files": [
{
"path": "registry/example/infinity-text-demo.tsx",
"type": "registry:example"
}
]
},
{
"name": "utils",
"type": "registry:lib",
Expand Down
Loading