Blog Blocks for Shadcn and React
Simple blog grid
import { Badge } from '@/components/ui/badge'
interface BlogPost {
id: string
title: string
description: string
image?: string
date: string
category: string
}
interface Props {
title?: string
description?: string
posts?: BlogPost[]
}
const samplePosts: BlogPost[] = [
{
id: '1',
title: 'Building Modern Web Applications',
description:
'Discover the latest techniques and best practices for creating stunning, performant web applications that users love. Learn about cutting-edge frameworks and tools.',
image: 'https://picsum.photos/1600/960?random=1',
date: '2024-12-15',
category: 'Development',
},
{
id: '2',
title: 'The Future of UI Components',
description:
'Explore how component libraries are evolving and what this means for developers. From design systems to accessibility, we cover it all.',
image: 'https://picsum.photos/1600/960?random=2',
date: '2024-12-10',
category: 'Design',
},
{
id: '3',
title: 'Optimizing Performance at Scale',
description:
'Deep dive into performance optimization strategies that matter. Learn how to make your applications blazingly fast without compromising features.',
image: 'https://picsum.photos/1600/960?random=3',
date: '2024-12-05',
category: 'Performance',
},
]
export default function BlogSectionOne({
title = 'Latest Articles',
description = 'Insights, tutorials, and updates from our team.',
posts = samplePosts,
}: Props) {
return (
<section className="w-full bg-background py-12 md:py-16">
<div className="container mx-auto px-4 md:px-6">
<div className="mb-8 text-center md:mb-12">
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
{title}
</h2>
<p className="mt-3 text-muted-foreground">{description}</p>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{posts.map(post => (
<article
key={post.id}
className="group relative flex flex-col overflow-hidden rounded-lg transition"
>
{post.image && (
<div className="pointer-events-none relative aspect-video w-full overflow-hidden rounded-lg">
<img
src={post.image}
alt={post.title}
className="size-full select-none object-cover transition-transform duration-300 group-hover:scale-105"
/>
</div>
)}
<div className="flex flex-col gap-2 p-4">
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Badge variant="outline">
{post.category}
</Badge>
<time dateTime={post.date}>
{new Date(post.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})}
</time>
</div>
<h2 className="text-xl font-semibold">
<a href={`#${post.id}`} className="after:absolute after:inset-0">
{post.title}
</a>
</h2>
<p className="line-clamp-4 text-muted-foreground">
{post.description}
</p>
</div>
</article>
))}
</div>
</div>
</section>
)
} Block details
A clean and minimal blog section featuring a responsive grid layout with article cards. Each card displays an image, publication date, title, and description with hover effects. Perfect for showcasing blog posts in a simple, elegant manner.
| Dependency | Source |
|---|---|
| Badge (shadcn) | Registry |
Blog card section
import { ChevronRightIcon } from 'lucide-react'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import {
Card,
CardDescription,
CardHeader,
CardTitle,
} from '@/components/ui/card'
interface BlogPost {
id: string
title: string
description: string
image: string
date: string
category: string
}
interface Props {
badge?: string
title?: string
description?: string
posts?: BlogPost[]
showViewAll?: boolean
viewAllText?: string
}
const samplePosts: BlogPost[] = [
{
id: '1',
title: 'Building Modern Web Applications',
description:
'Discover the latest techniques and best practices for creating stunning, performant web applications that users love. Learn about cutting-edge frameworks and tools.',
image: 'https://picsum.photos/1600/960?random=1',
date: '2024-12-15',
category: 'Development',
},
{
id: '2',
title: 'The Future of UI Components',
description:
'Explore how component libraries are evolving and what this means for developers. From design systems to accessibility, we cover it all.',
image: 'https://picsum.photos/1600/960?random=2',
date: '2024-12-10',
category: 'Design',
},
{
id: '3',
title: 'Optimizing Performance at Scale',
description:
'Deep dive into performance optimization strategies that matter. Learn how to make your applications blazingly fast without compromising features.',
image: 'https://picsum.photos/1600/960?random=3',
date: '2024-12-05',
category: 'Performance',
},
]
export default function BlogSectionTwo({
title = 'From the Blog',
description = 'Insights, tutorials, and updates from our team. Stay up to date with the latest in web development and design.',
posts = samplePosts,
showViewAll = true,
viewAllText = 'View all articles',
}: Props) {
return (
<section className="bg-background py-16 px-4 sm:px-6 lg:px-8">
<div className="mx-auto max-w-7xl">
<div className="flex flex-col md:flex-row md:justify-between md:items-center mb-8 md:mb-12">
<div className="text-left mb-4 md:mr-4">
<h2 className="text-3xl font-bold tracking-tight sm:text-4xl">
{title}
</h2>
<p className="mt-3 text-muted-foreground">{description}</p>
</div>
{showViewAll && (
<div>
<Button className="group">
{viewAllText}
<ChevronRightIcon className="size-4 transition-transform group-hover:translate-x-0.5" />
</Button>
</div>
)}
</div>
<div className="grid gap-8 md:grid-cols-2 lg:grid-cols-3">
{posts.map(post => (
<Card
key={post.id}
className="group relative overflow-hidden pt-0"
>
<div className="relative aspect-video w-full overflow-hidden">
<img
src={post.image}
alt={post.title}
className="size-full object-cover"
/>
</div>
<CardHeader>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<Badge variant="outline">
{post.category}
</Badge>
<time dateTime={post.date}>
{new Date(post.date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})}
</time>
</div>
<CardTitle className="text-xl">
<a href={`#${post.id}`} className="after:absolute after:inset-0">
{post.title}
</a>
</CardTitle>
<CardDescription className="line-clamp-3">
{post.description}
</CardDescription>
<div className="flex justify-start items-center gap-1 text-sm font-medium text-primary">
Read more
<ChevronRightIcon className="size-4 transition-transform group-hover:translate-x-0.5" />
</div>
</CardHeader>
</Card>
))}
</div>
</div>
</section>
)
} Block details
An advanced blog section with premium design featuring category badges, gradient overlays, and smooth hover animations. Includes a customizable header with badge, title, and description, plus an optional View All button. Built with Shadcn Card components for a polished, professional look.
| Dependency | Source |
|---|---|
| Badge (shadcn) | Registry |
| Card (shadcn) | Registry |
| Button (shadcn) | Registry |
| Lucide React | NPM |
Frequently asked questions
How do I customize the blog posts data?
Both blog sections accept a `posts` prop where you can pass your own array of blog post objects. Each post should include fields like id, title, description, image, and date. The components use default sample data if no props are provided, making them easy to preview and test.
Are these blog sections responsive?
Yes, both blog sections are fully responsive. They use a CSS grid layout that automatically adapts from a single column on mobile devices to 2 columns on tablets and 3 columns on desktop screens. All images and text elements scale appropriately for different viewport sizes.
Can I customize the grid layout and number of columns?
Absolutely! The grid layout uses Tailwind CSS classes like "md:grid-cols-2 lg:grid-cols-3". You can easily modify these values to change the number of columns at different breakpoints. For example, change to "md:grid-cols-3 lg:grid-cols-4" for a 4-column desktop layout.
What image aspect ratio should I use for blog post images?
Both sections use a 16:9 aspect ratio (aspect-video) for blog post images. This creates a consistent, professional look across all cards. Images are set to "object-cover" to maintain the aspect ratio while filling the container, and "object-top" ensures the top portion of images is always visible.
Are the blog blocks free to use?
We offer both free and premium blog blocks. The free blocks are completely free to use in personal and commercial projects. Premium blocks require a one-time purchase for access to more advanced designs.
How do I use these blog blocks in my project?
Simply browse our collection, click on the "Copy Code" button for your chosen block, and paste it into your Shadcn React project. All components are built with Tailwind CSS & Shadcn React, so they'll work seamlessly with your existing setup.
Can I customize the blog blocks?
Absolutely! All our blog blocks are fully customizable. You can easily modify colors, spacing, typography, and layout by adjusting the Tailwind CSS classes in the component code.