Components / Blocks
BlogGrid
A blog index with a featured post, category filter, post cards, pagination and an in-place reader.
Install
npx shadcn@latest add https://irisui.dev/r/blog-grid.jsonimport { BlogGrid } from "@/components/iris/blocks/blog-grid/blog-grid";Preview
BlogGrid
A blog index with a featured post, a category filter, a grid of post cards, pagination and an in-place reader that opens a post without leaving the page.
When to use
- The index page of a blog, journal, changelog essays or customer stories.
- When posts have a cover image, a category, an author and a reading time.
- Not for release notes with versions and dates per change: use
ChangelogFeed. - Not for a short "latest posts" strip in a footer or sidebar; render a simple list instead.
Usage
import { BlogGrid } from "@/components/iris/blocks/blog-grid/blog-grid";
h(BlogGrid, {
title: "The notdocs blog",
description: "Release notes, design decisions and engineering write-ups.",
categories: ["Product", "Design", "Engineering", "Company"],
posts: [
{
id: "files-in-your-repo",
featured: true,
category: "Product",
date: "2026-10-06",
readTime: 7,
author: { name: "Katerina Vlachou", role: "Product lead", avatar: "/people/katerina.jpg" },
title: "Your workspace is a folder in your repo",
excerpt: "Pages, tasks and decisions are markdown files, and nothing syncs.",
image: { src: "/covers/files-in-your-repo.jpg", alt: "A document tree beside its markdown file" },
body: ["First paragraph.", "Second paragraph."],
},
],
pageSize: 6,
getHref: undefined, // pass (post) => `/blog/${post.id}` to link out instead of the reader
});
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title / description |
string |
"Blog", sample line | Heading and supporting text. |
posts |
BlogPost[] |
13 sample notdocs posts | { id, title, excerpt, category, date (ISO), readTime (minutes), author: { name, avatar?, role? }, image?: { src, alt }, body?: string[], featured? }. |
categories |
string[] |
Product, Design, Engineering, Company | Filter labels in order; "All" is added in front. |
category / defaultCategory / onCategoryChange |
string |
"All" |
Active category (controlled / uncontrolled). |
page / defaultPage / onPageChange |
number |
1 |
One-based page (controlled / uncontrolled). |
pageSize |
number |
6 |
Cards per page below the featured post. |
showFeatured |
boolean |
true |
Shows the newest post of the current filter as a large card on page one. |
getHref |
(post) => string |
none | When set, cards are links and the in-place reader is off. |
onPostOpen |
(post) => void |
none | Called when a post opens, from a link or the reader. |
className |
string |
none | Extra class on the section. |
Notes
- The default posts are a sample notdocs blog with one flat inline SVG cover and no portraits; pass your own
posts. - An author without
avatarshows a plain placeholder circle (no initials). - The reader morphs the card image into the article header (shared layout); reduced motion replaces the morph with a fade.
- Dates are formatted from the ISO string; posts are sorted newest first.