All-Access · 23 templates$1319.97$99/year — save 92%Get access
  • HomeHome
  • TemplatesTemplates17+
  • ComponentsComponents80+
  • PricingPricing
  • Need a Website?Need a Website?New
Unlock All AccessUnlock All Access

Our latest template collection

Ready-to-launch sites for real estate agents, service businesses, and local brands — built to rank, load fast, and convert.

Explore All TemplatesExplore All Templates

Orvaine - Luxury Equestrian & Horse Breeding Website Template

Orvaine is a premium website template for stud farms, sport horse breeders and equestrian estates: horse pages with pedigrees, events, films. Next.js, Astro, Sanity.

Download Template
Orvaine - Luxury Equestrian & Horse Breeding Website Template

Maressa - Luxury Yacht Charter & Sales Website Template

Maressa is a premium website template for yacht charter, brokerage and superyacht brands: 21 editable sections, full-screen films, Next.js and Astro versions. Sanity.

Download Template
Maressa - Luxury Yacht Charter & Sales Website Template

Krishi – Agriculture & Farm Website Template

Krishi is a premium website template for farms, agritech and food brands: 17 editable sections, cinematic GSAP motion and both Next.js and Astro versions. Built with Sanity.

Download Template
Krishi – Agriculture & Farm Website Template
ComponentsFeaturesBlog Cards
FreeReactTailwind CSSNext.js

Blog Cards

A blog preview with three post cards showing category, author, date, reading time and excerpt. React and Tailwind CSS, no dependencies.

View codeView code
Full screen
BlogCards.tsx
// Blog preview: heading with an "All articles" link, then three post cards
// with category tag, author, date, reading time and excerpt.
// Pure Tailwind, no dependencies. Works with Tailwind v3 and v4.

type Post = {
  title: string;
  excerpt: string;
  category: string;
  image: string;
  author: { name: string; photo: string };
  date: string;
  minutes: number;
  href?: string;
};

type Props = {
  eyebrow?: string;
  heading?: string;
  allLink?: { label: string; href: string };
  posts?: Post[];
};

const img = (id: string, w = 900) => `https://images.unsplash.com/photo-${id}?w=${w}&q=80&auto=format&fit=crop`;
const face = (id: string) => `https://images.unsplash.com/photo-${id}?w=80&h=80&q=80&auto=format&fit=crop&crop=faces`;

const DEFAULT_POSTS: Post[] = [
  { title: "Ten questions to ask before you make an offer", excerpt: "From survey results to service charges, the details that separate a good buy from an expensive lesson.", category: "Buying", image: img("1512917774080-9991f1c4c750"), author: { name: "Alexandra Morrison", photo: face("1573496359142-b8d87734a5a2") }, date: "Mar 12, 2026", minutes: 6 },
  { title: "Staging a home that sells in the first week", excerpt: "Light, space and a little restraint: what buyers notice in the first thirty seconds of a viewing.", category: "Selling", image: img("1560184897-cca79b749615"), author: { name: "Daniel Mercer", photo: face("1507003211169-0a1dd7228f2d") }, date: "Feb 28, 2026", minutes: 4 },
  { title: "Is now a good time to buy a holiday home?", excerpt: "Rates, rental yields and the coastal towns where prices are still sensible this year.", category: "Market", image: img("1564013799919-ab600027ffc6"), author: { name: "Isabelle Torres", photo: face("1534528741775-53994a69daeb") }, date: "Feb 9, 2026", minutes: 8 },
];

const Arrow = ({ className = "" }: { className?: string }) => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" aria-hidden className={className}>
    <path d="M5 12h14M13 6l6 6-6 6" />
  </svg>
);

export default function BlogCards({
  eyebrow = "Insights & advice",
  heading = "Latest from our blog",
  allLink = { label: "All articles", href: "#" },
  posts = DEFAULT_POSTS,
}: Props) {
  return (
    <section className="bg-[#faf7f2] px-5 py-20 font-['Manrope',ui-sans-serif,system-ui,sans-serif] antialiased md:px-10 md:py-28">
      <div className="mx-auto max-w-7xl">
        <div className="mb-14 flex flex-wrap items-end justify-between gap-6">
          <div>
            <span className="mb-3 block text-xs font-bold uppercase tracking-[0.2em] text-[#F66F00]">{eyebrow}</span>
            <h2 className="font-['Bricolage_Grotesque',ui-sans-serif,system-ui,sans-serif] text-[clamp(36px,5vw,64px)] font-semibold leading-[1.1] text-neutral-900">{heading}</h2>
          </div>
          <a href={allLink.href} className="inline-flex items-center gap-2 rounded-full border border-neutral-900 px-6 py-3 text-sm font-semibold text-neutral-900 transition-colors hover:bg-neutral-900 hover:text-white">
            {allLink.label} <Arrow className="h-4 w-4" />
          </a>
        </div>

        <div className="grid grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-3">
          {posts.map((post) => (
            <a key={post.title} href={post.href ?? "#"} className="group block overflow-hidden bg-white transition-shadow duration-300 hover:shadow-xl">
              <div className="relative aspect-[16/9] overflow-hidden">
                <img src={post.image} alt={post.title} className="absolute inset-0 h-full w-full object-cover transition-transform duration-700 group-hover:scale-105" />
                <span className="absolute left-3 top-3 rounded-full bg-white/95 px-3 py-1 text-[0.65rem] font-semibold uppercase tracking-widest text-black">{post.category}</span>
              </div>
              <div className="p-6">
                <div className="mb-4 flex items-center gap-3">
                  <img src={post.author.photo} alt={post.author.name} className="h-8 w-8 rounded-full object-cover" />
                  <div>
                    <div className="text-xs font-semibold text-neutral-900">{post.author.name}</div>
                    <div className="text-xs text-neutral-400">{post.date}</div>
                  </div>
                  <div className="ml-auto text-xs text-neutral-400">{post.minutes} min read</div>
                </div>
                <h3 className="mb-3 line-clamp-2 font-['Bricolage_Grotesque',ui-sans-serif,system-ui,sans-serif] text-xl font-semibold leading-snug text-neutral-900">{post.title}</h3>
                <p className="line-clamp-3 text-sm leading-relaxed text-neutral-500">{post.excerpt}</p>
                <div className="mt-5 flex items-center gap-1.5 text-sm font-semibold text-[#F66F00]">
                  Read more <Arrow className="h-3.5 w-3.5 transition-transform group-hover:translate-x-1" />
                </div>
              </div>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
}

How to use it

  1. Make sure your Next.js or React project has Tailwind CSS set up.
  2. Create components/BlogCards.tsx and paste the code.
  3. Import it into a page and replace the placeholder text and images with your own.
EstateHaven - Real Estate Website Template for Next.js & Sanity
From the full template
EstateHaven - Real Estate Website Template for Next.js & Sanity$49

This section is one part of EstateHaven - Real Estate Website Template for Next.js & Sanity: a complete website with every page, Sanity CMS and SEO already set up.

Get the full template Get the full template Live preview Live preview

More free components

All features →
Count-Up Stats

Count-Up Stats

Numbered Process Steps

Numbered Process Steps

About Section with Stats

About Section with Stats

Ready for a faster site that's easier to edit?

Book a free 30-minute call. We'll review your current site and send a fixed-price plan. No pressure, no pitch.

Book Free Call Book Free Call No commitment required

Fast Next.js + Sanity websites, built for you or ready to launch with our templates.

Book a Free Call Book a Free Call
Services
  • Web Design
  • UI/UX Design
  • Framer Dev
  • Webflow Dev
  • Custom Dev
  • Sanity CMS
Resources
  • Templates
  • Pricing
  • License
  • Components
  • Case Studies
Company
  • About Us
  • Contact
  • Privacy Policy
© 2026 rayso.studio — All rights reservedDesigned & built in-house Remote-first agency
Let's TalkLet's Talk