# 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/blog49. 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 Ledger

# Quad Ledger[PRO](/pricing)

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.

ViewCodeDocs

Base UI

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

## Blog49: Quad Ledger

An image-free blog index that opens with a `Badge6` eyebrow and a two-column heading band above a hairline rule, then lists linked stories as bordered cards where every card pairs a zero-padded accent counter with a bold headline, a category-and-date kicker, a summary, and a byline. No image is rendered anywhere in the block, and an optional `Button1` seal button closes the section below the grid.

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/blog49?email=YOUR_EMAIL&license_key=YOUR_KEY"
```

**Base UI flavor**

bashCopy

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

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

### Quick start

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

tsxCopy

```
import { Blog49, blog49Demo } from "@/components/beste/block/blog49";

export default function Page() {
  return <Blog49 {...blog49Demo} />;
}
```

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

tsxCopy

```
import { Blog49 } from "@/components/beste/block/blog49";

export default function Page() {
  return (
    <Blog49
      label="Press office"
      heading="Company announcements"
      description="Statements and filings issued by the communications office, listed in order of release."
      items={[
        {
          category: "Operations",
          title: "Second storage site opens in Aragon",
          summary:
            "The facility connects to the regional transmission network in April.",
          date: "February 4, 2026",
          author: { name: "Maria Santos", title: "Tech Lead" },
          href: "/press/aragon-storage",
        },
        {
          category: "Governance",
          title: "Board appoints a new audit committee chair",
          summary:
            "The appointment takes effect at the close of the annual general meeting.",
          date: "January 27, 2026",
          author: { name: "David Chen" },
          href: "/press/audit-chair",
        },
      ]}
      button={{ label: "Full press archive", href: "/press" }}
    />
  );
}
```

### Props

| Prop        | Type         | Default | Description                                                               |
| ----------- | ------------ | ------- | ------------------------------------------------------------------------- |
| label       | string       | –       | Badge6 eyebrow above the heading; omitted entirely when absent            |
| heading     | string       | –       | Heading in the left column of the heading band                            |
| description | string       | –       | Muted supporting paragraph in the right column, capped at max-w-md        |
| items       | Article\[\]  | \[\]    | Story cards rendered into the grid                                        |
| button      | ActionButton | –       | Button1 seal button centered below the grid; omitted entirely when absent |
| className   | string       | –       | Extra classes merged onto the outer <section>                             |

tsCopy

```
type Article = {
  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;
};

type ActionButton = {
  label: string;
  href: string;
};
```

### Behavior notes

* Two independent breakpoints drive the layout. The heading band stacks until `md`, where it splits into two columns and the description bottom-aligns to the right edge. The story grid stacks until `sm`, where it becomes two columns; the heading band therefore stays single-column while the grid is already paired.
* Cards are separated by a real `gap-6` and each carries its own border, so an odd item count simply leaves the trailing cell empty instead of stranding a rule. The rule under the heading band always renders, with or without `label`, `heading`, and `description`.
* The block is not fixed at four items despite the 2x2 preview. The counter is `String(index + 1).padStart(2, "0")`, so it reads `01` through `09` and then widens to `10` and beyond without truncating.
* `author.avatar` and `author.href` exist on the interface but are never rendered: the byline is plain text built as `By {name}` with `, {title}` appended only when `title` is set, and the avatar is dropped because the whole card is already a single Next.js `Link` to `item.href`. The kicker joins `category` and `date` with a middot and prints both verbatim with no date formatting.
* Hover is styling only: the headline shifts to `text-primary` on card hover. Cards are keyed by array `index` rather than `href`, so reordering `items` remounts rather than reorders them.

## More Blog blocks

[View all Blog](/blocks/blog)

[](/block/blog48)

PRO

blog48

### Quad Grid

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.

[](/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/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/blog47)

PRO

blog47

### Bulletin Columns

A newsroom bulletin with a square eyebrow, an image-free lead story split across a 7/5 grid with a standfirst, byline, and a seal button, then three illustrated columns with hover-zoom images below a single hairline rule.

[](/block/blog52)

PRO

blog52

### Newsroom Masonry

A CSS-columns masonry of linked newsroom cards under a parenthetical eyebrow and a large heading, where the image aspect ratio cycles by position so the wall keeps an uneven, magazine-like rhythm.

[](/block/blog55)

PRO

blog55

### Press Release Wall

A three-column wall of image-free press release cards on soft muted surfaces under a parenthetical eyebrow and a large heading, each card pairing a release type and date with a headline, dek, byline, and a ruled category row.

## 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.