Blog grid
A blog index with a featured post, category filter, post cards, pagination and an in-place reader.
Journal
Product news, design notes and engineering deep dives from the team.

The case for quiet software
Why we removed half the colors from our interface and people started finishing work faster.

How offline sync actually works
Conflict free replicated data, explained with the bugs we hit on the way to shipping it.

What we learned from a week in Lisbon
Forty people, one shared roadmap, and no slides allowed. Notes from our autumn offsite.

Shared views are here
Save a filter, name it, and share it with your team. Everyone sees the same thing, always current.

Choosing a type scale you will not regret
Seven sizes, two weights, and the rules we use to keep them that way as the product grows.

Making search ten times faster
A new query planner, a smarter index, and one very embarrassing N plus one we found along the way.

The rituals that keep a remote team close
Written standups, demo Fridays and the one meeting we will never cancel.
When to use
- A marketing site blog or journal index.
- Resource hubs with a few categories and a featured story.
When not to use
- Use changelog-page for release notes with versions.
- Use a data table for large archives that need sorting and search.
shadcn CLI
Also installs (1)
- manicat-foundation
Manual install(+)
{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "blog-grid",
"type": "registry:block",
"title": "Blog grid",
"description": "A blog index with a featured post, category filter, post cards, pagination and an in-place reader.",
"categories": [
"blocks"
],
"dependencies": [
"lucide-react",
"motion"
],
"registryDependencies": [
"https://manicat.viraza.net/r/manicat-foundation.json"
],
"files": [
{
"path": "registry/blocks/blog-grid/blog-grid.tsx",
"type": "registry:component",
"target": "@components/manicat/blocks/blog-grid/blog-grid.tsx"
},
{
"path": "registry/blocks/blog-grid/blog-grid-data.ts",
"type": "registry:component",
"target": "@components/manicat/blocks/blog-grid/blog-grid-data.ts"
},
{
"path": "registry/blocks/blog-grid/blog-grid.module.css",
"type": "registry:component",
"target": "@components/manicat/blocks/blog-grid/blog-grid.module.css"
}
],
"docs": "Docs and live preview: https://uiarc.dev/components/blocks/blog-grid",
"meta": {
"tier": "free",
"kind": "block",
"docs": "https://manicat.viraza.net/components/blocks/blog-grid",
"markdown": "https://uiarc.dev/components/blocks/blog-grid/markdown"
}
}Usage
Install the component, then copy this into your app. Change the content and the props to fit your screen.
"use client";
import { BlogGrid } from "manicat/registry/blocks/blog-grid/blog-grid";
export function BlogGridExample() {
return <BlogGrid />;
}
Examples
Real screens rather than isolated props. Switch to Code to copy a whole example into your project.
Blog index A filterable grid with featured post and pagination.
From the blog
Notes on design and engineering.

The case for quiet software
Why we removed half the colors from our interface and people started finishing work faster.

How offline sync actually works
Conflict free replicated data, explained with the bugs we hit on the way to shipping it.

What we learned from a week in Lisbon
Forty people, one shared roadmap, and no slides allowed. Notes from our autumn offsite.

Shared views are here
Save a filter, name it, and share it with your team. Everyone sees the same thing, always current.

Choosing a type scale you will not regret
Seven sizes, two weights, and the rules we use to keep them that way as the product grows.

Making search ten times faster
A new query planner, a smarter index, and one very embarrassing N plus one we found along the way.

The rituals that keep a remote team close
Written standups, demo Fridays and the one meeting we will never cancel.
"use client";
import { BlogGrid } from "manicat/registry/blocks/blog-grid/blog-grid";
export function BlogGridIndexExample() {
return <BlogGrid title="From the blog" description="Notes on design and engineering." pageSize={6} showFeatured />;
}
Keyboard interactions
| Keys | Action |
|---|---|
| Tab | Moves through filters, cards, and pagination. |
| Enter | Opens the focused post, or picks the focused filter or page. |
| Space | Picks the focused filter or page. |
Accessibility
- Filters are buttons with aria-pressed; pagination is a nav with aria-current on the active page.
- Each card is one link with the title, excerpt and byline as its content, so screen readers announce it once.
- The reader moves focus to its back button, and closing returns focus to the card you opened.
- Images carry real alt text; author avatars are decorative.
Motion
- The filter and page highlights glide on the morph spring.
- Filtering crossfades the grid with a short rise; paging slides it in the direction of travel.
- Opening a post morphs the card image into the reader hero, and back on close.
- Card images zoom 3% on hover (fine pointers only).
- Reduced motion swaps travel and morphs for plain fades.
Responsive behavior
- Three columns above 900px, two to 540px, then one.
- The featured post stacks its image above the text below 680px.
- Filters scroll sideways on phones; Previous and Next collapse to arrows.
Performance
- Only one page of cards renders at a time; images below the fold load lazily.
- Transitions animate transform and opacity only.
Notes for AI
- Choose this for a blog, journal, news or resources index.
- Pass getHref for real article routes; leave it out for a self-contained demo or a small site that reads posts in place.
- Drive category and page from the URL with the controlled props so the index is linkable.