---
title: Blog
description: Blog layouts for featured stories, cards, and reading lists.
group: Blocks
order: 14
---

A small set of blog layouts, from quick scans to denser indexes. Bring your own stories, covers, and authors.

## Post cards

Three straightforward cards with a cover, category, title, and excerpt.

```tsx
"use client";

import { cn } from "@/lib/utils";

type Blog01Props = {
  className?: string;
};

const POSTS = [
  {
    title: "Shipping blocks that match your tokens",
    excerpt: "How we keep every section restylable without a second design pass.",
    category: "Product",
    date: "Mar 12, 2026",
    image: "/assets/brand/demos/attachments/attachment-1.png",
  },
  {
    title: "A boring install story on purpose",
    excerpt: "CLI, drop-in, ship — why the path to first paint should feel uneventful.",
    category: "Engineering",
    date: "Mar 4, 2026",
    image: "/assets/brand/demos/attachments/attachment-2.png",
  },
  {
    title: "Light, dark, and everything between",
    excerpt: "Semantic surfaces so marketing pages don’t need a night-mode rewrite.",
    category: "Design",
    date: "Feb 21, 2026",
    image: "/assets/brand/demos/attachments/attachment-3.png",
  },
] as const;

export function Blog01({ className }: Blog01Props) {
  return (
    <section className={cn("@container w-full bg-background", className)}>
      <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14">
        <div className="mx-auto max-w-md text-center">
          <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl">
            From the blog
          </h2>
          <p className="mt-2 text-sm tracking-wide text-muted-foreground">
            Notes on product, design, and shipping interfaces that feel finished.
          </p>
        </div>
        <ul className="mt-8 grid grid-cols-1 gap-6 @[40rem]:grid-cols-3 @[40rem]:gap-4">
          {POSTS.map((post) => (
            <li key={post.title} className="flex min-w-0 flex-col">
              <div className="aspect-[16/10] w-full overflow-hidden rounded-xl bg-muted">
                <img
                  src={post.image}
                  alt=""
                  className="size-full object-cover"
                />
              </div>
              <div className="mt-3 flex items-center justify-between gap-3 text-[11px] tracking-wide text-muted-foreground">
                <span>{post.category}</span>
                <span>{post.date}</span>
              </div>
              <h3 className="mt-1.5 line-clamp-2 text-sm font-medium tracking-wide text-foreground">
                {post.title}
              </h3>
              <p className="mt-1.5 line-clamp-2 text-xs tracking-wide text-muted-foreground">
                {post.excerpt}
              </p>
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}
```

### Installation

```bash
npx @arctis-sh/@arctis-sh/ui@latest add blog-01
```

### Usage

```tsx
import { Blog01 } from "@/components/blocks/blog/blog-01"
```

```tsx
<Blog01 />
```

## Featured + row

One full-width feature followed by three smaller posts in a row.

```tsx
"use client";

import { cn } from "@/lib/utils";

type Blog02Props = {
  className?: string;
};

const FEATURED = {
  title: "Shipping a full marketing kit",
  excerpt: "Patterns that held up when teams started installing blocks.",
  category: "Product",
  date: "Mar 18, 2026",
  image: "/assets/brand/demos/attachments/attachment-4.png",
} as const;

const POSTS = [
  {
    title: "Token-ready defaults",
    excerpt: "Restyle every section without a second design pass.",
    category: "Design",
    date: "Mar 10, 2026",
    image: "/assets/brand/demos/attachments/attachment-1.png",
  },
  {
    title: "Keep the CLI boring",
    excerpt: "Install, import, ship — no ceremony required.",
    category: "Engineering",
    date: "Mar 2, 2026",
    image: "/assets/brand/demos/attachments/attachment-2.png",
  },
  {
    title: "Compose without fights",
    excerpt: "Mix heroes, pricing, and FAQs in any order.",
    category: "Guides",
    date: "Feb 24, 2026",
    image: "/assets/brand/demos/attachments/attachment-3.png",
  },
] as const;

export function Blog02({ className }: Blog02Props) {
  return (
    <section className={cn("@container w-full bg-background", className)}>
      <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14">
        <div className="mx-auto max-w-md text-center">
          <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl">
            Latest writing
          </h2>
          <p className="mt-2 text-sm tracking-wide text-muted-foreground">
            A featured story up top, then three recent posts underneath.
          </p>
        </div>

        <article className="relative mt-8 aspect-[21/9] overflow-hidden rounded-xl bg-muted @[32rem]:aspect-[2.4/1]">
          <img
            src={FEATURED.image}
            alt=""
            className="absolute inset-0 size-full object-cover"
          />
          <div className="absolute inset-0 bg-gradient-to-t from-black/70 via-black/20 to-transparent" />
          <div className="absolute inset-x-0 bottom-0 p-4 @[32rem]:p-6">
            <p className="text-[11px] tracking-wide text-white/75">
              {FEATURED.category}
              <span className="mx-1.5 text-white/40">·</span>
              {FEATURED.date}
            </p>
            <h3 className="mt-1.5 line-clamp-2 text-sm font-medium tracking-wide text-white @[32rem]:text-base">
              {FEATURED.title}
            </h3>
            <p className="mt-1.5 line-clamp-2 max-w-xl text-xs tracking-wide text-white/75">
              {FEATURED.excerpt}
            </p>
          </div>
        </article>

        <ul className="mt-8 grid grid-cols-1 gap-6 @[40rem]:grid-cols-3 @[40rem]:gap-4">
          {POSTS.map((post) => (
            <li key={post.title} className="flex min-w-0 flex-col">
              <div className="aspect-[16/10] w-full overflow-hidden rounded-xl bg-muted">
                <img
                  src={post.image}
                  alt=""
                  className="size-full object-cover"
                />
              </div>
              <div className="mt-3 flex items-center justify-between gap-3 text-[11px] tracking-wide text-muted-foreground">
                <span>{post.category}</span>
                <span>{post.date}</span>
              </div>
              <h3 className="mt-1.5 line-clamp-2 text-sm font-medium tracking-wide text-foreground">
                {post.title}
              </h3>
              <p className="mt-1.5 line-clamp-2 text-xs tracking-wide text-muted-foreground">
                {post.excerpt}
              </p>
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}
```

### Installation

```bash
npx @arctis-sh/@arctis-sh/ui@latest add blog-02
```

### Usage

```tsx
import { Blog02 } from "@/components/blocks/blog/blog-02"
```

```tsx
<Blog02 />
```

## Reading list

Compact rows with covers, excerpts, and authors for a denser reading index.

```tsx
"use client";

import { cn } from "@/lib/utils";

type Blog03Props = {
  className?: string;
};

const POSTS = [
  {
    title: "Shipping blocks that match your tokens",
    excerpt: "Keep every section restylable without a second design pass.",
    category: "Product",
    date: "Mar 12, 2026",
    author: "Maya Chen",
    avatar: "/assets/brand/demos/avatars/avatar-1.png",
    image: "/assets/brand/demos/attachments/attachment-1.png",
  },
  {
    title: "A boring install story on purpose",
    excerpt: "Why the path to first paint should feel uneventful.",
    category: "Engineering",
    date: "Mar 4, 2026",
    author: "Priya Nair",
    avatar: "/assets/brand/demos/avatars/avatar-3.png",
    image: "/assets/brand/demos/attachments/attachment-2.png",
  },
  {
    title: "Light, dark, and everything between",
    excerpt: "Semantic surfaces so night mode isn’t a rewrite.",
    category: "Design",
    date: "Feb 21, 2026",
    author: "Jordan Hale",
    avatar: "/assets/brand/demos/avatars/avatar-2.png",
    image: "/assets/brand/demos/attachments/attachment-3.png",
  },
  {
    title: "Composing pages without layout fights",
    excerpt: "Mix heroes, pricing, and FAQs without nesting wars.",
    category: "Guides",
    date: "Feb 14, 2026",
    author: "Chris Ortega",
    avatar: "/assets/brand/demos/avatars/avatar-4.png",
    image: "/assets/brand/demos/attachments/attachment-5.png",
  },
] as const;

export function Blog03({ className }: Blog03Props) {
  return (
    <section className={cn("@container w-full bg-background", className)}>
      <div className="mx-auto w-full max-w-3xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14">
        <div className="mx-auto max-w-md text-center">
          <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl">
            All posts
          </h2>
          <p className="mt-2 text-sm tracking-wide text-muted-foreground">
            A simple reading list with author and cover on each row.
          </p>
        </div>
        <ul className="mt-8 flex flex-col gap-3">
          {POSTS.map((post) => (
            <li
              key={post.title}
              className="flex gap-4 rounded-xl bg-muted p-3 @[32rem]:p-4"
            >
              <div className="hidden size-24 shrink-0 overflow-hidden rounded-lg bg-background @[32rem]:block">
                <img
                  src={post.image}
                  alt=""
                  className="size-full object-cover"
                />
              </div>
              <div className="flex min-w-0 flex-1 flex-col justify-center">
                <div className="flex items-center justify-between gap-3 text-[11px] tracking-wide text-muted-foreground">
                  <span>{post.category}</span>
                  <span>{post.date}</span>
                </div>
                <h3 className="mt-1 line-clamp-2 text-sm font-medium tracking-wide text-foreground">
                  {post.title}
                </h3>
                <p className="mt-1 line-clamp-2 text-xs tracking-wide text-muted-foreground">
                  {post.excerpt}
                </p>
                <div className="mt-3 flex items-center gap-2">
                  <img
                    src={post.avatar}
                    alt=""
                    className="size-5 rounded-full object-cover"
                  />
                  <span className="text-[11px] tracking-wide text-muted-foreground">
                    {post.author}
                  </span>
                </div>
              </div>
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}
```

### Installation

```bash
npx @arctis-sh/@arctis-sh/ui@latest add blog-03
```

### Usage

```tsx
import { Blog03 } from "@/components/blocks/blog/blog-03"
```

```tsx
<Blog03 />
```
