# Feature 197 - Feature accordion with paired image panel

> A two-column section built around an accordion that switches feature copy and updates the large preview image beside the list.

A shadcn/ui block from the [@shadcnblocks](https://shadcnblocks.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcnblocks/feature197).

- Page, with a live preview: https://shadcn.exchange/r/shadcnblocks/feature197
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcnblocks/feature197-light-4137ec023585e017.png
- Registry item: https://shadcnblocks.com/r/feature197.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcnblocks.com/r/feature197.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `cn`
- Registry items: `accordion`

## Files

### `block/feature197/feature197.tsx`

```tsx
"use client";

import { useState } from "react";
import { cn } from "cn";

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion";
interface FeatureItem {
  id: number;
  title: string;
  image: string;
  description: string;
}

interface Feature197Props {
  features: FeatureItem[];
  className?: string;
}

const Feature197 = ({
  features = [
    {
      id: 1,
      title: "Shadcn UI Blocks",
      image:
        "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/lummi/bw12.jpeg",
      description:
        "Browse through our extensive collection of pre-built UI blocks designed with shadcn/ui at shadcnblocks.com. Each block is carefully crafted to be responsive, accessible, and easily customizable.",
    },
    {
      id: 2,
      title: "Tailwind CSS & TypeScript",
      image:
        "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/lummi/bw15.jpeg",
      description:
        "Built with Tailwind CSS for rapid styling and TypeScript for type safety. Our blocks leverage the full power of Tailwind's utility classes while maintaining clean, type-safe code.",
    },
    {
      id: 3,
      title: "Dark Mode & Customization",
      image:
        "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/lummi/bw20.jpeg",
      description:
        "Every block supports dark mode out of the box and can be customized to match your brand. Modify colors, spacing, and typography using Tailwind's configuration.",
    },
    {
      id: 4,
      title: "Accessibility First",
      image:
        "https://deifkwefumgah.cloudfront.net/shadcnblocks/block/lummi/bw21.jpeg",
      description:
        "All blocks are built with accessibility in mind, following WCAG guidelines. They include proper ARIA labels, keyboard navigation, and semantic HTML.",
    },
  ],
  className,
}: Feature197Props) => {
  const [activeTabId, setActiveTabId] = useState<number | null>(1);
  const [activeImage, setActiveImage] = useState(features[0].image);

  return (
    <section className={cn("py-32", className)}>
      <div className="container mx-auto">
        <h2 className="mb-12 text-3xl font-semibold md:text-4xl">Features</h2>
        <div className="flex w-full items-start justify-between gap-12">
          <div className="w-full md:w-1/2">
            <Accordion
              type="single"
              collapsible
              className="w-full"
              defaultValue="item-1"
            >
              {features.map((tab) => (
                <AccordionItem
                  key={tab.id}
                  value={`item-${tab.id}`}
                  className="transition-opacity hover:opacity-80"
                >
                  <AccordionTrigger
                    onClick={() => {
                      setActiveImage(tab.image);
                      setActiveTabId(tab.id);
                    }}
                    className="cursor-pointer py-5 no-underline! transition"
                  >
                    <h4
                      className={`text-xl ${tab.id === activeTabId ? "text-foreground" : "text-muted-foreground"}`}
                    >
                      {tab.title}
                    </h4>
                  </AccordionTrigger>
                  <AccordionContent className="pb-2">
                    <p className="text-base text-muted-foreground">
                      {tab.description}
                    </p>
                    <div className="mt-4 md:hidden">
                      <img
                        src={tab.image}
                        alt={tab.title}
                        className="h-full max-h-80 w-full rounded-md object-cover"
                      />
                    </div>
                  </AccordionContent>
                </AccordionItem>
              ))}
            </Accordion>
          </div>
          <div className="relative hidden w-1/2 overflow-hidden rounded-xl bg-muted md:block">
            <div className="relative aspect-4/3">
              {features.map((feature) => (
                <img
                  key={feature.id}
                  src={feature.image}
                  alt={feature.title}
                  className={cn(
                    "absolute inset-0 h-full w-full rounded-md object-cover transition-opacity duration-500",
                    activeImage === feature.image ? "opacity-100" : "opacity-0",
                  )}
                />
              ))}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
};

export { Feature197 };
```
