Components
A React hook that provides automatic scrolling behavior for containers with dynamic content, particularly useful for chat interfaces, message lists, and real-time feeds.
Features
Loading preview...
'use client'
import { useState } from "react"
import { useAutoScroll } from "@/components/hooks/use-auto-scroll"
import { Button } from "@/components/ui/button"
import { ArrowDown } from "lucide-react"
function AutoScrollDemo() {
const [messages, setMessages] = useState<string[]>([
"Initial message",
"Second message",
"Third message",
])
const { scrollRef, isAtBottom, autoScrollEnabled, scrollToBottom } = useAutoScroll({
offset: 20,
smooth: true,
content: messages,
})
const addMessage = () => {
setMessages(prev => [...prev, `Message ${prev.length + 1}`])
}
return (
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 p-8 max-w-4xl mx-auto">
{/* Demo Container */}
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-lg font-medium">Auto-Scrolling Messages</h3>
<p className="text-sm text-muted-foreground">
Add messages or scroll manually to see the behavior
</p>
</div>
<div className="relative border rounded-lg bg-muted/30">
<div
ref={scrollRef}
className="h-[300px] overflow-y-auto p-4 space-y-2"
>
{messages.map((msg, i) => (
<div key={i} className="p-3 bg-background rounded-lg shadow-sm">
{msg}
</div>
))}
</div>
{!isAtBottom && (
<Button
size="icon"
variant="outline"
className="absolute bottom-4 right-4 rounded-full"
onClick={scrollToBottom}
>
<ArrowDown className="h-4 w-4" />
</Button>
)}
</div>
<Button onClick={addMessage}>Add Message</Button>
</div>
{/* Status Panel */}
<div className="space-y-4">
<div className="space-y-2">
<h3 className="text-lg font-medium">Scroll Status</h3>
<p className="text-sm text-muted-foreground">
Current state of the auto-scroll behavior
</p>
</div>
<div className="space-y-2 p-4 border rounded-lg">
<div className="flex justify-between items-center">
<span className="text-sm font-medium">Is At Bottom:</span>
<span className={isAtBottom ? "text-green-500" : "text-yellow-500"}>
{isAtBottom ? "Yes" : "No"}
</span>
</div>
<div className="flex justify-between items-center">
<span className="text-sm font-medium">Auto-Scroll Enabled:</span>
<span className={autoScrollEnabled ? "text-green-500" : "text-yellow-500"}>
{autoScrollEnabled ? "Yes" : "No"}
</span>
</div>
</div>
</div>
{/* Documentation */}
<div className="md:col-span-2">
<div className="space-y-4 p-6 border rounded-lg">
<h3 className="text-lg font-medium">About useAutoScroll</h3>
<div className="space-y-4">
<pre className="bg-muted p-4 rounded-md text-xs overflow-x-auto">
{`const { scrollRef, isAtBottom, autoScrollEnabled, scrollToBottom } = useAutoScroll({
offset: 20, // Distance threshold to consider "at bottom"
smooth: true, // Use smooth scrolling
content: data // Content to watch for changes
})`}
</pre>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
<div>
<h4 className="font-medium mb-2">Features</h4>
<ul className="list-disc list-inside space-y-1 text-muted-foreground">
<li>Automatic scroll to bottom</li>
<li>Manual scroll detection</li>
<li>Smooth scrolling support</li>
<li>Content change detection</li>
</ul>
</div>
<div>
<h4 className="font-medium mb-2">Use Cases</h4>
<ul className="list-disc list-inside space-y-1 text-muted-foreground">
<li>Chat applications</li>
<li>Feed interfaces</li>
<li>Log viewers</li>
<li>Real-time updates</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export { AutoScrollDemo }