Features — Alternating

Alternating image and text sections to showcase features.

Features badge

Installation

npx shadcn@latest add @saastro/features-02

Preview

Built for developers

Blocks designed to accelerate your workflow.

Performance

Zero JS by default

In Astro, React components render as pure HTML on the server. No JavaScript shipped unless you add client directives.

Image
Customizable

Make it yours

Every block uses standard Tailwind CSS classes and shadcn/ui components. Customize colors, spacing, and typography with CSS variables.

Image

Source Code

import { Badge } from '@/components/ui/badge';
import { cn } from '@/lib/utils';

type Feature = {
  badge?: string;
  title: string;
  description: string;
  imageSrc?: string;
  imageAlt?: string;
};

type Features02Props = {
  title?: string;
  description?: string;
  features: Feature[];
  className?: string;
};

export function Features02({ title, description, features, className }: Features02Props) {
  return (
    <section className={cn('w-full px-6 py-24 md:py-32', className)}>
      <div className="mx-auto max-w-6xl">
        {(title || description) && (
          <div className="mx-auto mb-20 max-w-2xl text-center">
            {title && <h2 className="text-3xl font-bold tracking-tight sm:text-4xl">{title}</h2>}
            {description && <p className="mt-4 text-lg text-muted-foreground">{description}</p>}
          </div>
        )}
        <div className="flex flex-col gap-20">
          {features.map((feature, index) => (
            <div
              key={index}
              className={cn(
                'grid items-center gap-12 lg:grid-cols-2',
                index % 2 === 1 && 'lg:direction-rtl',
              )}
            >
              <div className={cn(index % 2 === 1 && 'lg:order-2')}>
                {feature.badge && (
                  <Badge variant="secondary" className="mb-4">
                    {feature.badge}
                  </Badge>
                )}
                <h3 className="text-2xl font-bold tracking-tight sm:text-3xl">{feature.title}</h3>
                <p className="mt-4 text-muted-foreground">{feature.description}</p>
              </div>
              <div
                className={cn(
                  'aspect-video overflow-hidden rounded-xl border bg-muted',
                  index % 2 === 1 && 'lg:order-1',
                )}
              >
                {feature.imageSrc ? (
                  <img
                    src={feature.imageSrc}
                    alt={feature.imageAlt ?? ''}
                    className="h-full w-full object-cover"
                  />
                ) : (
                  <div className="flex h-full w-full items-center justify-center bg-gradient-to-br from-muted to-muted-foreground/5">
                    <span className="text-2xl text-muted-foreground/30">Image</span>
                  </div>
                )}
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}

Registry Setup

Add the Saastro registry to your components.json:

{
  "registries": {
    "@saastro": "https://ui.saastro.io/r/{name}.json"
  }
}