# Features Alternating

Alternating image and text rows that slide in from opposite sides as you scroll.

**Kind:** section · Features  
**Styles:** Light, Minimal  
**Built from:** scroll-reveal  
**Live preview:** https://charcoalui.com/preview/section/features-alternating

## Install

```bash
npx shadcn@latest add https://charcoalui.com/r/features-alternating.json
```
Lands in `components/sections/features-alternating.tsx` and installs every component it uses.

## Props (all optional, for your copy)

```ts
export type FeaturesAlternatingProps = {
  rows?: AlternatingRow[];
};
```

## Source

```tsx
"use client";

import { ArrowRight } from "lucide-react";
import { ScrollReveal } from "@/components/ui/scroll-reveal";

const BASE = "https://charcoalui.com/demo";

export type AlternatingRow = { eyebrow: string; title: string; body: string; image: string; link?: string };

export type FeaturesAlternatingProps = {
  rows?: AlternatingRow[];
};

export function FeaturesAlternating({
  rows = [
    { eyebrow: "Identity", title: "A mark that holds up at sixteen pixels", body: "We draw logos at favicon size first, then scale up. If it reads on a browser tab, it reads on a billboard.", image: `${BASE}/forest.webp`, link: "Read the Ember Records story" },
    { eyebrow: "Product", title: "Interfaces that feel considered, not decorated", body: "Spacing, type and motion decided as a system, so the hundredth screen looks like it belongs with the first.", image: `${BASE}/fog.webp`, link: "See the Glow app" },
    { eyebrow: "Motion", title: "Movement with a reason behind it", body: "Every transition explains something: where a thing came from, where it went, or what just changed.", image: `${BASE}/night.webp`, link: "Watch the reel" },
  ],
}: FeaturesAlternatingProps) {
  return (
    <section className="overflow-x-clip bg-background">
      <div className="mx-auto grid max-w-6xl gap-24 px-6 py-24 sm:py-32">
        {rows.map((r, i) => (
          <div key={r.title} className="grid grid-cols-1 items-center gap-10 lg:grid-cols-2 lg:gap-16">
            <ScrollReveal from={i % 2 ? "right" : "left"} className={i % 2 ? "lg:order-2" : ""}>
              <img src={r.image} alt="" className="aspect-[4/3] w-full rounded-2xl border object-cover" />
            </ScrollReveal>
            <ScrollReveal from={i % 2 ? "left" : "right"} delay={0.1}>
              <p className="font-mono text-[11px] uppercase tracking-[0.1em] text-ember">{r.eyebrow}</p>
              <h3 className="mt-3 text-3xl font-semibold tracking-tight text-balance sm:text-4xl">{r.title}</h3>
              <p className="mt-4 max-w-md text-pretty text-lg leading-8 text-muted-foreground">{r.body}</p>
              {r.link && (
                <a href="#" className="group mt-6 inline-flex items-center gap-2 text-sm font-medium underline decoration-ember underline-offset-4">
                  {r.link}
                  <ArrowRight className="size-4 transition-transform group-hover:translate-x-0.5" />
                </a>
              )}
            </ScrollReveal>
          </div>
        ))}
      </div>
    </section>
  );
}
```