Examples
Scroll Seek Placeholders
Render lightweight placeholders while a virtual feed scrolls quickly.
Scroll seek is useful when real cards are expensive. While velocity is high, Masonix renders placeholders that keep the same layout size.
Example
import { useRef } from 'react';
type FeedItem = {
id: string;
author: string;
handle: string;
topic: string;
body: string;
note?: string;
tags: string[];
metric: string;
gradient: string;
};
function FeedCard({ item }: { item: FeedItem }) {
return (
<article
className={clsx(
'overflow-hidden',
'rounded-xl border',
'border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-950',
)}
>
<div className="p-4" style={{ background: item.gradient }}>
<div className="flex items-center justify-between gap-3">
<span className="rounded-full bg-white/85 px-2 py-1 text-xs font-medium text-zinc-900">
{item.topic}
</span>
<span className="text-xs font-medium text-white/80">
{item.metric}
</span>
</div>
<p className="mt-8 text-xs font-medium leading-5 text-white/80">
{item.tags.join(' / ')}
</p>
</div>
<div className="p-4">
<div>
<h3 className="text-sm font-semibold text-zinc-950 dark:text-zinc-50">
{item.author}
</h3>
<p className="text-xs text-zinc-500">{item.handle}</p>
</div>
<p className="mt-3 text-sm leading-6 text-zinc-600 dark:text-zinc-400">
{item.body}
</p>
{item.note ? (
<p className="mt-3 rounded-lg bg-zinc-100 p-3 text-xs leading-5 text-zinc-600 dark:bg-zinc-900 dark:text-zinc-400">
{item.note}
</p>
) : null}
<div className="mt-4 flex flex-wrap gap-2">
{item.tags.map((tag) => (
<span
key={tag}
className="rounded-full border border-zinc-200 px-2 py-1 text-xs text-zinc-500 dark:border-zinc-800"
>
{tag}
</span>
))}
</div>
</div>
</article>
);
}
function FeedSkeleton({
height,
}: MasonryRenderProps<FeedItem> & { height: number }) {
return (
<div
className={clsx(
'flex flex-col overflow-hidden',
'rounded-xl border',
'border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-950',
)}
style={{ height }}
>
<div className="h-24 shrink-0 animate-pulse bg-zinc-100 dark:bg-zinc-900" />
<div className="space-y-3 p-4">
<div className="h-3 w-1/2 rounded-full bg-zinc-100 dark:bg-zinc-900" />
<div className="h-3 w-5/6 rounded-full bg-zinc-100 dark:bg-zinc-900" />
<div className="h-3 w-2/3 rounded-full bg-zinc-100 dark:bg-zinc-900" />
<div className="h-3 w-1/3 rounded-full bg-zinc-100 dark:bg-zinc-900" />
</div>
</div>
);
}
export function FastFeed({ items }: { items: FeedItem[] }) {
const scrollContainerRef = useRef<HTMLDivElement>(null);
return (
<div
ref={scrollContainerRef}
className={clsx(
'min-w-0 overflow-x-hidden overflow-y-auto overscroll-contain',
'h-96 p-3',
'rounded-lg border',
'border-zinc-200 dark:border-zinc-800',
)}
>
<MasonryVirtual
items={items}
columns={{ 0: 1, 600: 2 }}
gap={12}
estimatedItemHeight={280}
scrollContainer={scrollContainerRef}
scrollSeek={{
velocityThreshold: 900,
placeholder: FeedSkeleton,
}}
itemKey={(item) => item.id}
render={({ data }) => <FeedCard item={data} />}
/>
</div>
);
}When to use
Use this when cards include expensive media, charts, syntax highlighting, or heavy interactive controls.
Notes
- Placeholder height should be used directly.
- Keep placeholders visually quiet.
- Real item keys, positions, and measurements remain intact.