Pinterest-style masonry layout with varying content heights. CSS columns create organic flow with cards of different summary lengths.
A Pinterest-style blog index that flows post cards through CSS multi-column layout (one, two, or three columns responsively), each card showing a hover-zoomed cover image, an optional outline tag badge, a title, a full summary, an author avatar with name, and a read time, above an optional centered header of badge, heading, and description.
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://ui.beste.co/r/blog12?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/blog12?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/blog12.tsx, plus the badge and avatar shadcn/ui primitives it uses for the tag/eyebrow badges and the author avatars.
The installed file exports blog12Demo alongside the block: the exact props behind the preview above. Spread it to get a working masonry blog grid in one line.
import { Blog12, blog12Demo } from "@/components/beste/block/blog12";
export default function Page() {
return <Blog12 {...blog12Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Blog12 } from "@/components/beste/block/blog12";
export default function Page() {
return (
<Blog12
badge={{ label: "Explore", variant: "default" }}
heading="Discover Articles"
description="A curated collection of our best content."
posts={[
{
image: { src: "/covers/design-systems.jpg", alt: "Design systems" },
title: "The Future of Design Systems",
summary: "How design systems evolve to meet complex web apps.",
date: "January 15, 2026",
readTime: "8 min read",
author: {
name: "Lisa Park",
title: "Senior Developer",
avatar: { src: "/avatars/lisa.jpg", alt: "Lisa Park" },
},
tags: [{ label: "Design", href: "/blog/design" }],
href: "/blog/future-of-design-systems",
},
]}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | { label: string; variant?: "default" | "secondary" | "outline" } | – | Optional centered eyebrow badge above the heading |
heading | string | – | Section heading rendered as <h2> |
description | string | – | Muted sub-copy under the heading |
posts | BlogPost[] | [] | Cards flowed through the CSS column grid |
className | string | – | Extra classes merged onto the outer <section> |
type Author = {
name: string;
title?: string;
avatar?: { src: string; alt: string };
href?: string;
};
type Tag = {
label: string;
href?: string;
};
type BlogPost = {
image: { src: string; alt: string };
title: string;
summary: string;
date?: string;
readTime?: string;
author?: Author;
tags?: Tag[];
href?: string;
};columns-1 sm:columns-2 lg:columns-3 with break-inside-avoid on each card, so card order flows top-to-bottom within each column and card heights vary with summary length; there is no JavaScript reflow or virtualization.summary is always rendered with no line clamp, which is what drives the varying card heights that create the Pinterest effect; long summaries produce tall cards.post.tags?.[0] alone, so any additional entries in a post's tags array are silently ignored.next/link Link; when a post.href, tag.href, or nothing is provided it falls back to href="#", and author.href is accepted in the type but never wired to a link.post.date is accepted in the BlogPost type but is never rendered; only readTime appears in the card footer, aligned opposite the author block.author.name.split(" ") first letters when no avatar image loads; if author is omitted the whole author block is hidden and the read time sits alone.badge, heading, or description is provided, and badge.variant defaults to "default" when omitted.blog43
A blog listing with an eyebrow over a hairline rule, a two-column heading, and three linked article cards with a hover-zoom image, a monospace category, a title, an excerpt, and byline.
blog3
Three-column responsive grid of blog cards featuring author avatars, tag badges, and hover zoom effects. Clean card design with date and read time metadata.
blog14
Four-column grid mixing blog cards with an integrated newsletter signup card. Email input and subscribe button embedded in the layout.
blog30
Grid of image cards with gradient overlays. Summaries expand on hover with smooth max-height animation. Titles always visible with white text.
blog11
Two-column compact blog list with small square thumbnails. Space-efficient design showing many posts at once with minimal metadata.
blog25
Two-column layout with featured image on left and article list on right. Divider-separated entries with arrow hover effects.