# Blog 8 - Blog post rows with tags and large images

> Two wide blog post rows, each with uppercase tags, a large title, excerpt, author, date, and read-more link beside an image, under a centered heading.

A shadcn/ui block from the [@shadcnblocks](https://shadcnblocks.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcnblocks/blog8).

- Page, with a live preview: https://shadcn.exchange/r/shadcnblocks/blog8
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcnblocks/blog8-light-4280787227a861c6.png
- Registry item: https://shadcnblocks.com/r/blog8.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcnblocks.com/r/blog8.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `cn`, `lucide-react`
- Registry items: `card`

## Files

### `block/blog8/blog8.tsx`

```tsx
import { cn } from "cn";
import { ArrowRight } from "lucide-react";

import { Card } from "@/components/ui/card";

interface BlogRowPost {
  id?: string;
  title: string;
  summary?: string;
  href?: string;
  image?: Image;
  logo?: Image;
  team?: string;
  category?: string;
  tags?: string[];
  date?: string;
  readTime?: string;
  author?: string;
  role?: string;
  avatar?: Image;
  initials?: string;
  cta?: string;
}
interface Image {
  src: string;
  alt: string;
  srcDark?: string;
}

interface BlogRowProps {
  heading: string;
  description?: string;
  posts: BlogRowPost[];
  className?: string;
}

interface Blog8Props extends BlogRowProps {}
type Props = Partial<Blog8Props>;

const person1 = {
  name: "Jack Walsh",
  firstName: "Jack",
  lastName: "Walsh",
  initials: "JW",
  email: "jack.walsh@example.com",
  username: "jackwalsh",
  role: "Product Designer",
  company: "Cartwright",
  location: "Brisbane, Australia",
  avatar: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/avatars/avatar1.webp",
};
const person2 = {
  name: "Ilze Pērkone",
  firstName: "Ilze",
  lastName: "Pērkone",
  initials: "MK",
  email: "iperkone@example.com",
  username: "iperkone",
  role: "Brand Director",
  company: "Kivit",
  location: "Rīga, Latvia",
  avatar: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/avatars/avatar2.webp",
};
const person3 = {
  name: "Vernon Desilets",
  firstName: "Vernon",
  lastName: "Desilets",
  initials: "VD",
  email: "vernod@example.com",
  username: "vernod",
  role: "Creative Director",
  company: "Soho Logix",
  location: "Paris, France",
  avatar: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/avatars/avatar3.webp",
};
const person4 = {
  name: "Lín Wàngshū",
  firstName: "Lín",
  lastName: "Wangshu",
  initials: "LW",
  email: "linwang4@example.com",
  username: "liwang",
  role: "Graphic Designer",
  company: "Tenxcloud",
  location: "Shanghai, China",
  avatar: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/avatars/avatar4.webp",
};
const person5 = {
  name: "Rajesh Bhatt",
  firstName: "Rajesh",
  lastName: "Bhatt",
  initials: "RB",
  email: "rajesh.bhatt@example.com",
  username: "rajeshbhatt",
  role: "UX Researcher",
  company: "Mindtree",
  location: "Mumbai, India",
  avatar: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/avatars/avatar5.webp",
};
const person6 = {
  name: "Jessica Cannon",
  firstName: "Jessica",
  lastName: "Cannon",
  initials: "JC",
  email: "jessica.cannon@example.com",
  username: "jessicacannon",
  role: "Data Analyst",
  company: "Fidelity Investments",
  location: "Boston, USA",
  avatar: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/avatars/avatar6.webp",
};
const defaultProps: Blog8Props = {
  heading: "Blog",
  description: "Notes on design, product, and the work of building software.",
  posts: [
    {
      id: "post-1",
      title: "What changed in interface design this year",
      summary:
        "A look at the patterns that stuck, and the ones that quietly disappeared.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-1-16x9.jpg",
        alt: "Colleagues working at a shared desk",
      },
      category: "Design",
      tags: ["Design", "Product"],
      date: "March 12, 2026",
      readTime: "6 min",
      author: person1.name,
      role: person1.role,
      avatar: {
        src: person1.avatar,
        alt: person1.name,
      },
      initials: person1.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-1.svg",
        alt: person1.company,
      },
      team: person1.company,
    },
    {
      id: "post-2",
      title: "A practical guide to modern JavaScript",
      summary:
        "The language features we reach for, and the ones we leave alone.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-2-16x9.jpg",
        alt: "A team gathered for a presentation",
      },
      category: "Technology",
      tags: ["Technology", "Engineering"],
      date: "March 4, 2026",
      readTime: "8 min",
      author: person2.name,
      role: person2.role,
      avatar: {
        src: person2.avatar,
        alt: person2.name,
      },
      initials: person2.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-2.svg",
        alt: person2.company,
      },
      team: person2.company,
    },
    {
      id: "post-3",
      title: "Campaigns that still earn their keep",
      summary:
        "What held up after the novelty wore off, told with the numbers we kept.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-3-16x9.jpg",
        alt: "A desk with a desktop computer",
      },
      category: "Marketing",
      tags: ["Marketing", "Editorial"],
      date: "February 24, 2026",
      readTime: "5 min",
      author: person3.name,
      role: person3.role,
      avatar: {
        src: person3.avatar,
        alt: person3.name,
      },
      initials: person3.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-3.svg",
        alt: person3.company,
      },
      team: person3.company,
    },
    {
      id: "post-4",
      title: "How product teams write decisions down",
      summary:
        "A simple record of why a choice was made, written so the next person can find it.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-4-16x9.jpg",
        alt: "Two colleagues talking by a window",
      },
      category: "Design",
      tags: ["Design", "Product"],
      date: "February 18, 2026",
      readTime: "11 min",
      author: person4.name,
      role: person4.role,
      avatar: {
        src: person4.avatar,
        alt: person4.name,
      },
      initials: person4.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-4.svg",
        alt: person4.company,
      },
      team: person4.company,
    },
    {
      id: "post-5",
      title: "Accessible interfaces without a redesign",
      summary:
        "Small changes that make a page easier to use without a new visual system.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-5-16x9.jpg",
        alt: "Three people collaborating around a laptop",
      },
      category: "Technology",
      tags: ["Technology", "Engineering"],
      date: "February 9, 2026",
      readTime: "7 min",
      author: person5.name,
      role: person5.role,
      avatar: {
        src: person5.avatar,
        alt: person5.name,
      },
      initials: person5.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-5.svg",
        alt: person5.company,
      },
      team: person5.company,
    },
    {
      id: "post-6",
      title: "Shipping faster without skipping review",
      summary: "How review stays in the path when the calendar gets tight.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-6-16x9.jpg",
        alt: "A person writing on a glass wall",
      },
      category: "Marketing",
      tags: ["Marketing", "Editorial"],
      date: "January 28, 2026",
      readTime: "9 min",
      author: person6.name,
      role: person6.role,
      avatar: {
        src: person6.avatar,
        alt: person6.name,
      },
      initials: person6.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-6.svg",
        alt: person6.company,
      },
      team: person6.company,
    },
    {
      id: "post-7",
      title: "Measuring what a launch actually did",
      summary:
        "The questions we ask a week later, once the launch post has gone quiet.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-7-16x9.jpg",
        alt: "Colleagues talking in a warm-lit office",
      },
      category: "Design",
      tags: ["Design", "Product"],
      date: "January 19, 2026",
      readTime: "4 min",
      author: person1.name,
      role: person1.role,
      avatar: {
        src: person1.avatar,
        alt: person1.name,
      },
      initials: person1.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-1.svg",
        alt: person1.company,
      },
      team: person1.company,
    },
    {
      id: "post-8",
      title: "The case for fewer tools",
      summary: "Fewer dashboards, fewer logins, and a clearer week.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-8-16x9.jpg",
        alt: "People talking at an office gathering",
      },
      category: "Technology",
      tags: ["Technology", "Engineering"],
      date: "January 8, 2026",
      readTime: "12 min",
      author: person2.name,
      role: person2.role,
      avatar: {
        src: person2.avatar,
        alt: person2.name,
      },
      initials: person2.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-2.svg",
        alt: person2.company,
      },
      team: person2.company,
    },
    {
      id: "post-9",
      title: "Photography, type, and the quiet page",
      summary: "How pictures and type share a page without competing.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-9-16x9.jpg",
        alt: "A team meeting around a high table",
      },
      category: "Marketing",
      tags: ["Marketing", "Editorial"],
      date: "December 16, 2025",
      readTime: "6 min",
      author: person3.name,
      role: person3.role,
      avatar: {
        src: person3.avatar,
        alt: person3.name,
      },
      initials: person3.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-3.svg",
        alt: person3.company,
      },
      team: person3.company,
    },
    {
      id: "post-10",
      title: "Notes on performance budgets",
      summary: "A budget for weight, and what we cut when a page misses it.",
      href: "#",
      image: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/blog-corporate/photo-10-16x9.jpg",
        alt: "A person working at a desktop computer",
      },
      category: "Design",
      tags: ["Design", "Product"],
      date: "December 4, 2025",
      readTime: "8 min",
      author: person4.name,
      role: person4.role,
      avatar: {
        src: person4.avatar,
        alt: person4.name,
      },
      initials: person4.initials,
      cta: "Read article",
      logo: {
        src: "https://cdn.shadcnblocks.com/shadcnblocks/image-set/modern/logos/fictional-company-logo-4.svg",
        alt: person4.company,
      },
      team: person4.company,
    },
  ],
};

const MAX_POSTS = 2;

const Blog8 = (props: Props) => {
  const { heading, description, posts, className } = {
    ...defaultProps,
    ...props,
  };

  const items = (posts ?? []).slice(0, MAX_POSTS);

  return (
    <section className={cn("py-32", className)}>
      <div className="container mx-auto">
        <div className="flex flex-col items-center gap-12">
          <header className="flex flex-col items-center gap-4 text-center">
            <h2 className="max-w-3xl text-3xl font-semibold tracking-tight text-balance md:text-4xl lg:text-5xl">
              {heading}
            </h2>
            <p className="max-w-2xl text-lg font-medium text-pretty text-muted-foreground md:text-xl">
              {description}
            </p>
          </header>

          <div className="flex w-full flex-col gap-16">
            {items.map((post, index) => (
              <Card
                key={post.id ?? index}
                className="w-full gap-0 border-0 bg-transparent p-0 py-0 shadow-none ring-0"
              >
                <div className="grid gap-y-6 sm:grid-cols-2 sm:gap-x-5 md:items-center md:gap-x-8 lg:gap-x-12">
                  <div className="flex flex-col gap-4">
                    <div className="flex flex-wrap gap-3 text-xs font-medium tracking-wide text-muted-foreground uppercase md:gap-5 lg:gap-6">
                      {(post.tags ?? []).map((tag) => (
                        <span key={tag}>{tag}</span>
                      ))}
                    </div>
                    <h3 className="text-xl font-semibold tracking-tight text-balance md:text-2xl lg:text-3xl">
                      <a
                        href={post.href}
                        target="_blank"
                        className="underline-offset-4 hover:underline focus-visible:underline focus-visible:outline-none"
                      >
                        {post.title}
                      </a>
                    </h3>
                    <p className="text-base leading-relaxed text-pretty text-muted-foreground">
                      {post.summary}
                    </p>
                    <div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-sm">
                      <span className="font-medium text-foreground">
                        {post.author}
                      </span>
                      <span
                        aria-hidden="true"
                        className="text-muted-foreground/40"
                      >
                        ·
                      </span>
                      <time className="text-muted-foreground tabular-nums">
                        {post.date}
                      </time>
                    </div>
                    <a
                      href={post.href}
                      target="_blank"
                      className="group/cue inline-flex items-center gap-1.5 text-sm font-medium underline-offset-4 hover:underline"
                    >
                      Read more
                      <ArrowRight className="size-4 text-muted-foreground transition-colors group-hover/cue:text-foreground" />
                    </a>
                  </div>
                  <div className="order-first sm:order-last">
                    <a
                      href={post.href}
                      tabIndex={-1}
                      aria-hidden="true"
                      target="_blank"
                      className="block overflow-hidden rounded-xl bg-muted"
                    >
                      <img
                        src={post.image?.src}
                        alt={post.image?.alt ?? ""}
                        className="aspect-16/9 h-full w-full object-cover transition-opacity duration-300 hover:opacity-90"
                      />
                    </a>
                  </div>
                </div>
              </Card>
            ))}
          </div>
        </div>
      </div>
    </section>
  );
};

export { Blog8 };
```
