# Beste UI

> Beautiful, accessible blocks, pieces and components for shadcn/ui and Tailwind CSS, built for React and Next.js. Install one with the shadcn CLI and the code is yours to edit: no runtime dependency, nothing to upgrade.

Markdown rendition of https://ui.beste.co/block/blog48. Every page on the site has one: add `.md` to any address, or send `Accept: text/markdown`.

Last updated: 2026-07-31

Whole catalog for LLMs: https://ui.beste.co/llms.txt. Registry index: https://ui.beste.co/r/registry.json

---
1. /
2. [Blocks](/blocks)
3. /
4. [Blog](/blocks/blog)
5. /
6. Quad Grid

# Quad Grid[PRO](/pricing)

A newsroom listing with a square eyebrow, a two-column heading band over a hairline rule, and four equally weighted stories as bordered cards, each linking through a hover-zoom image, a category kicker, a bold headline, a summary, and a byline pinned to the card foot.

ViewCodeDocs

Base UI

![](https://oud.pics/sm/l/npm.svg)`npx shadcn add https://ui.beste.co/r-base/blog48`

## Blog48: Quad Grid

A newsroom listing section that opens with a `Badge6` eyebrow and a two-column heading band above a hairline rule, then lays four equally weighted stories into a 2x2 grid of bordered cards where each cell links through a hover-zoom cover image, a category kicker, a bold headline, a summary, and a byline pinned to the foot of the card.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

[Upgrade NowUpgrade Now](/pricing)

### Installation

Swap `YOUR_EMAIL` and `YOUR_KEY` for the email and license key on your account. Find your license key on your [account page](/account).

**Radix flavor**

bashCopy

```
npx shadcn add "https://ui.beste.co/r/blog48?email=YOUR_EMAIL&license_key=YOUR_KEY"
```

**Base UI flavor**

bashCopy

```
npx shadcn add "https://ui.beste.co/r-base/blog48?email=YOUR_EMAIL&license_key=YOUR_KEY"
```

This installs the block to `components/beste/block/blog48.tsx` and its dependencies, including the `Badge6` component it renders.

### Quick start

The installed file exports `blog48Demo` alongside the block: the exact props behind the preview above. Spread it to get a working listing in one line.

tsxCopy

```
import { Blog48, blog48Demo } from "@/components/beste/block/blog48";

export default function Page() {
  return <Blog48 {...blog48Demo} />;
}
```

Then replace the demo with your own props. Written out, a trimmed setup looks like this:

tsxCopy

```
import { Blog48 } from "@/components/beste/block/blog48";

export default function Page() {
  return (
    <Blog48
      label="Press room"
      heading="Announcements from the Meridian communications desk"
      description="Filings, operating updates, and leadership changes, published as they are released."
      items={[
        {
          image: { src: "/press/harbour-terminal.jpg", alt: "Cranes above a container terminal at dusk" },
          category: "Operations",
          title: "Harbour terminal reopens after a nine-week refit",
          summary:
            "Berth three returns to full throughput this month, restoring the northern corridor to its pre-refit schedule.",
          date: "April 2, 2026",
          author: { name: "Ingrid Halvorsen", title: "Head of Communications" },
          href: "/press/harbour-terminal",
        },
        {
          image: { src: "/press/half-year.jpg", alt: "A printed results summary on a meeting table" },
          category: "Markets",
          title: "Half-year results hold margins flat against a softer freight index",
          summary:
            "Volumes tracked guidance and the board reaffirmed the payout policy set out in January.",
          date: "March 18, 2026",
          author: { name: "Tomas Weill", title: "Investor Relations" },
          href: "/press/half-year",
        },
      ]}
    />
  );
}
```

### Props

| Prop        | Type        | Default | Description                                                         |
| ----------- | ----------- | ------- | ------------------------------------------------------------------- |
| label       | string      | –       | Badge6 eyebrow above the heading band; omitted entirely when absent |
| heading     | string      | –       | Section heading in the left column of the heading band              |
| description | string      | –       | Muted supporting paragraph in the right column of the heading band  |
| items       | Article\[\] | \[\]    | Story cards rendered into the two-column grid                       |
| className   | string      | –       | Extra classes merged onto the outer <section>                       |

tsCopy

```
type Article = {
  image: { src: string; alt: string };
  category: string;
  title: string;
  summary: string;
  date: string;
  author: Author;
  href: string;
};

type Author = {
  name: string;
  title?: string;
  avatar?: { src: string; alt: string };
  href?: string;
};
```

### Behavior notes

* The grid is one column below the `sm` breakpoint and two columns from `sm` up, separated by a real `gap-6`. Each cell is its own bordered card, so an item count that is not a multiple of two simply leaves the last row half full rather than stranding a rule.
* Cards are flex columns and the byline is pushed to the foot with `mt-auto`, so a short summary and a long one still produce cards of equal height with their bylines aligned across the row.
* Each card wraps its image, kicker, headline, summary, and byline in one Next.js `Link` to `item.href`, tagged with the named group `group/blog48`. Hovering it scales the cover image to `scale-105` under a `motion-safe:` guard and shifts the headline to `text-primary`.
* The heading band is a `md:grid-cols-2` grid whose description sits in a `md:items-end md:justify-end` flex wrapper capped at `max-w-md`, so heading and description stack in source order below `md` and split left and right above it. All three of `label`, `heading`, and `description` are conditionally rendered and drop out cleanly when omitted; the rule under the band always renders.
* The byline prints only `author.name` and `date`, joined by a middot. The optional `title`, `avatar`, and `href` fields on `Author` are typed and accepted but never rendered.

## More Blog blocks

[View all Blog](/blocks/blog)

[](/block/blog43)

PRO

blog43

### Editorial Article Grid

A blog listing with an eyebrow over a hairline rule, a two-column heading, and three linked article cards with a hover-zoom image, a category label, a title, an excerpt, and byline.

[](/block/blog49)

PRO

blog49

### Quad Ledger

An image-free newsroom index with a square eyebrow, a two-column heading band over a hairline rule, four linked release cards that each pair an accent counter with a kicker, headline, dek, and byline, and a seal button to the full archive.

[](/block/blog46)

PRO

blog46

### Front Page Columns

A newsroom front page with a heading, a divider, and a square eyebrow over a hairline rule, a wide lead story whose headline and standfirst split across a twelve column band under a panoramic image, and the remaining articles set as three bordered text cards.

[](/block/blog44)

PRO

blog44

### Newsroom Lead and Index

A newsroom listing with a heading, a divider, and an eyebrow over a hairline rule, a two-column lead story with a large image, the remaining stories stacked as numbered ruled rows with square thumbnails, and a seal button to the full archive.

[](/block/blog56)

PRO

blog56

### Category Mosaic

A six-slot photo mosaic under a parenthetical eyebrow and a large heading, where every tile is bound to one newsroom category so the grid doubles as a section map, with a ruled legend naming the sections above it.

[](/block/blog14)

PRO

blog14

### Grid with Newsletter Card

Four-column grid mixing blog cards with an integrated newsletter signup card. Email input and subscribe button embedded in the layout.

## Ship the interface, keep the code.

New blocks, pieces and components every week. Install one with a command and it is yours to edit. No runtime dependency, no upgrade path to fight.

[Browse the libraryBrowse the library](/blocks)[See pricingSee pricing](/pricing)

### Library

* [Blocks](/blocks)
* [Pages](/pages)
* [Pieces](/pieces)
* [Components](/components)
* [Search](/search)

### Learn

* [Docs](/docs)
* [AI & MCP](/docs/mcp)
* [Blog](/blog)
* [Free tools](/tools)
* [What's new?](/changelog)
* [Website Builder](https://beste.co)

### More

* [Pricing](/pricing)
* [Referrals](/referrals)
* [License](/license)
* [GitHub](https://github.com/beste-co/beste-ui)

### Shadcn Blocks

* [Shadcn Hero Blocks](/blocks/hero)
* [Shadcn Feature Blocks](/blocks/feature)
* [Shadcn Pricing Blocks](/blocks/pricing)
* [Shadcn CTA Blocks](/blocks/cta)
* [Shadcn FAQ Blocks](/blocks/faq)
* [Shadcn About Blocks](/blocks/about)
* [Shadcn Stats Blocks](/blocks/stats)
* [Shadcn Footer Blocks](/blocks/footer)
* [Shadcn Navigation Blocks](/blocks/navigation)
* [Shadcn Auth Blocks](/blocks/auth)
* [Shadcn Ecommerce Blocks](/blocks/ecommerce)
* [Shadcn Portfolio Blocks](/blocks/portfolio)
* [Shadcn Showcase Blocks](/blocks/showcase)
* [Shadcn Careers Blocks](/blocks/careers)
* [Shadcn Onboarding Blocks](/blocks/onboarding)
* [Shadcn Coming Soon Blocks](/blocks/coming-soon)
* [Shadcn Post Blocks](/blocks/post)
* [Shadcn Legal Blocks](/blocks/legal)
* [Shadcn Workflow Blocks](/blocks/workflow)
* [Shadcn News Blocks](/blocks/news)

© 2026, [Beste](https://beste.co). All rights reserved.