Social Post Grid

About this block

Social Post GridPRO

A social proof grid of six linked post cards, each with an avatar, handle, timestamp, the post itself, and reply, repost, and like counts under a hairline.

Social49: Social Post Grid

A social proof grid of six linked post cards, each with an avatar, handle, timestamp, the post itself, and reply, repost and like counts under a hairline.

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 Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

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

Base UI flavor

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

This installs the block to components/beste/block/social49.tsx plus the badge23 and button21 components it uses for the eyebrow and the closing action.

Quick start

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

tsx
import { Social49, social49Demo } from "@/components/beste/block/social49";

export default function PostsPage() {
  return <Social49 {...social49Demo} />;
}

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

tsx
import { Social49 } from "@/components/beste/block/social49";

export default function PostsPage() {
  return (
    <Social49
      badge={{ label: "Said in public" }}
      heading="What practices posted without being asked to"
      description="None of these were solicited and none were paid for."
      posts={[
        {
          name: "Tom Ashby",
          handle: "@tomashby",
          avatar: { src: "/people/tom.jpg", alt: "Portrait of Tom Ashby" },
          body: "Four clinics, one waiting list, and the first Monday in years where nobody rang round.",
          time: "2h",
          replies: "12",
          reposts: "34",
          likes: "218",
          href: "https://example.com/post/1",
        },
        {
          name: "Elena Rourke",
          handle: "@elenarourke",
          avatar: { src: "/people/elena.jpg", alt: "Portrait of Elena Rourke" },
          body: "Eleven years of records moved over a weekend. I had budgeted three weeks.",
          time: "1d",
          replies: "31",
          reposts: "96",
          likes: "540",
          href: "https://example.com/post/2",
        },
      ]}
      button={{ label: "Read them in full", href: "/testimonials" }}
    />
  );
}

Props

PropTypeDefaultDescription
badge{ label: string }–Eyebrow above the hairline rule, rendered through Badge23
headingstring–Section heading in the left column of the header
descriptionstring–Supporting paragraph, right-aligned from md up
postsPost[][]Post cards, three across from lg
button{ label: string; href: string }–Centered outline action under the grid
classNamestring–Extra classes for the outer section
ts
type ActionLink = {
  label: string;
  href: string;
};

type Post = {
  name: string;
  handle: string;
  avatar: { src: string; alt: string };
  body: string;
  time: string;
  replies: string;
  reposts: string;
  likes: string;
  href: string;
};

Behavior notes

  • Engagement counts are strings, not numbers, so they can carry abbreviations like "1.2k" without the block needing to format anything. They use tabular-nums so the row stays steady.
  • The three engagement icons are aria-hidden, which means a screen reader hears three bare numbers. If that matters for your use, add visually hidden labels in the installed file.
  • Each card is a whole Link with a hover fill, so the entire post is one target pointing at the original thread.
  • Cards are flex flex-col with the body marked flex-1, so the engagement rows align along the bottom across every card in a row regardless of post length.
  • The header block uses min-w-0 with truncate on the name and handle, so a long handle ellipsizes rather than pushing the timestamp out of the row.
  • The engagement row carries its own border-t, so the rule belongs to the counts rather than sitting as a divider in the card.
  • The closing action wrapper is flex items-start justify-center. The items-start is load-bearing: without it the button would stretch vertically inside the centered flex row.
  • The grid is one, two, then three across, so six posts fill exactly two rows on desktop.

More Social blocks

View all Social
PRO

social50

Featured Post And Replies

PRO

social2

Social Post Card

PRO

social52

Community Sessions

Get Pro access