# Horizontal Scrolling Features

> A row of feature panels that scroll sideways as the page moves. Shows many product capabilities in a compact, playful strip that invites swiping.

A shadcn/ui block from the [@shadcn-ui-blocks](https://www.shadcn-ui-blocks.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcn-ui-blocks/ecommerce-product-features-horizontal-scrolling-features).

- Page, with a live preview: https://shadcn.exchange/r/shadcn-ui-blocks/ecommerce-product-features-horizontal-scrolling-features
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcn-ui-blocks/ecommerce-product-features-horizontal-scrolling-features-light-58ab5405fc051439.png
- Registry item: https://www.shadcn-ui-blocks.com/r/ecommerce-product-features-horizontal-scrolling-features.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://www.shadcn-ui-blocks.com/r/ecommerce-product-features-horizontal-scrolling-features.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: `class-variance-authority`, `lucide-react`, `radix-ui`

## Files

### `components/blocks/ecommerce/product-features/horizontal-scrolling-features.tsx`

```tsx
import { useRef } from 'react';

import {
  ArrowRight,
  ArrowLeft,
  Volume2,
  Music,
  Bluetooth,
  Waves,
  Wifi,
  Zap,
} from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';

export default function HorizontalScrollingFeatures() {
  const scrollContainerRef = useRef<HTMLDivElement>(null);

  const scrollLeft = () => {
    if (scrollContainerRef.current) {
      scrollContainerRef.current.scrollBy({ left: -300, behavior: 'smooth' });
    }
  };

  const scrollRight = () => {
    if (scrollContainerRef.current) {
      scrollContainerRef.current.scrollBy({ left: 300, behavior: 'smooth' });
    }
  };

  const features = [
    {
      id: 1,
      title: 'Hi-Res Audio',
      description:
        'Experience studio-quality sound with support for 24-bit/192kHz audio formats and lossless playback.',
      icon: <Music className="h-6 w-6" />,
      image:
        'https://images.unsplash.com/photo-1545454675-3531b543be5d?q=80&w=2070&auto=format&fit=crop',
      color: 'bg-blue-50 text-blue-600 dark:bg-blue-950/20 dark:text-blue-400',
    },
    {
      id: 2,
      title: '360° Sound Field',
      description:
        'Proprietary acoustic design projects crystal-clear audio in all directions with consistent quality from any listening position.',
      icon: <Volume2 className="h-6 w-6" />,
      image:
        'https://images.unsplash.com/photo-1608043152269-423dbba4e7e1?q=80&w=2069&auto=format&fit=crop',
      color:
        'bg-amber-50 text-amber-600 dark:bg-amber-950/20 dark:text-amber-400',
    },
    {
      id: 3,
      title: 'Multiroom Audio',
      description:
        'Seamlessly synchronize multiple speakers throughout your home for whole-house audio with zero latency.',
      icon: <Waves className="h-6 w-6" />,
      image:
        'https://images.unsplash.com/photo-1609702847389-b8aec1b0b929?q=80&w=1926&auto=format&fit=crop',
      color:
        'bg-purple-50 text-purple-600 dark:bg-purple-950/20 dark:text-purple-400',
    },
    {
      id: 4,
      title: 'Adaptive EQ',
      description:
        'Room-sensing technology automatically adjusts audio parameters based on speaker placement and room acoustics.',
      icon: <Bluetooth className="h-6 w-6" />,
      image:
        'https://images.unsplash.com/photo-1624913503273-5f9c4e980dba?q=80&w=1974&auto=format&fit=crop',
      color: 'bg-rose-50 text-rose-600 dark:bg-rose-950/20 dark:text-rose-400',
    },
    {
      id: 5,
      title: 'Voice Assistant',
      description:
        'Built-in microphone array with advanced noise cancellation for reliable voice control from across the room.',
      icon: <Wifi className="h-6 w-6" />,
      image:
        'https://images.unsplash.com/photo-1610123598195-eea6b6be4c48?q=80&w=1963&auto=format&fit=crop',
      color:
        'bg-emerald-50 text-emerald-600 dark:bg-emerald-950/20 dark:text-emerald-400',
    },
    {
      id: 6,
      title: 'Fast Charging',
      description:
        '10 hours of playback from a 15-minute charge via USB-C, with up to 50 hours of total battery life.',
      icon: <Zap className="h-6 w-6" />,
      image:
        'https://images.unsplash.com/photo-1558537348-c0f8e733989d?q=80&w=2070&auto=format&fit=crop',
      color:
        'bg-orange-50 text-orange-600 dark:bg-orange-950/20 dark:text-orange-400',
    },
  ];

  return (
    <section className="bg-background w-full overflow-hidden py-12 md:py-24 lg:py-32">
      <div className="container mx-auto px-4 md:px-6 2xl:max-w-[1400px]">
        <div className="mb-12 flex flex-col items-center space-y-4 text-center">
          <Badge className="px-3.5 py-1.5">Premium Sound</Badge>
          <h2 className="text-3xl font-bold tracking-tighter sm:text-4xl md:text-5xl">
            Audio engineering excellence
          </h2>
          <p className="text-muted-foreground max-w-[700px] md:text-xl/relaxed">
            Our premium speakers combine innovative technology with
            sophisticated design for an unparalleled listening experience.
          </p>
        </div>

        {/* Main product image */}
        <div className="mb-16 flex justify-center">
          <div className="relative aspect-[16/9] w-full max-w-3xl overflow-hidden rounded-xl border shadow-lg">
            <img
              src="https://images.unsplash.com/photo-1595433707802-6b2626ef1c91?q=80&w=2070&auto=format&fit=crop"
              alt="Premium wireless speaker"
              className="object-cover"
              sizes="(max-width: 768px) 100vw, 1000px"
            />
            <div className="absolute inset-0 flex items-end bg-gradient-to-t from-black/60 to-transparent">
              <div className="p-6 text-white">
                <Badge variant="secondary" className="mb-2">
                  Flagship Model
                </Badge>
                <h3 className="text-2xl font-semibold">SoundSphere X1</h3>
                <p className="mt-1 text-white/80">
                  Where art meets audio engineering
                </p>
              </div>
            </div>
          </div>
        </div>

        {/* Feature navigation buttons */}
        <div className="mb-4 flex justify-end space-x-2 md:pr-6">
          <Button
            variant="outline"
            size="icon"
            onClick={scrollLeft}
            aria-label="Scroll left"
          >
            <ArrowLeft className="h-4 w-4" />
          </Button>
          <Button
            variant="outline"
            size="icon"
            onClick={scrollRight}
            aria-label="Scroll right"
          >
            <ArrowRight className="h-4 w-4" />
          </Button>
        </div>

        {/* Horizontal scrolling features */}
        <div
          ref={scrollContainerRef}
          className="scrollbar-hide -mx-4 flex snap-x snap-mandatory space-x-4 overflow-x-auto px-4 pb-6 md:-mx-6 md:px-6"
          style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}
        >
          {features.map((feature) => (
            <div
              key={feature.id}
              className="group w-[280px] flex-shrink-0 snap-start overflow-hidden rounded-xl border transition-all duration-300 hover:shadow-lg md:w-[350px]"
            >
              <div className="relative h-48 overflow-hidden">
                <img
                  src={feature.image}
                  alt={feature.title}
                  className="object-cover transition-transform duration-500 group-hover:scale-105"
                  sizes="(max-width: 768px) 280px, 350px"
                />
                <div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent">
                  <div className="absolute bottom-4 left-4">
                    <div
                      className={cn(
                        'flex h-8 w-8 items-center justify-center rounded-full',
                        feature.color
                      )}
                    >
                      {feature.icon}
                    </div>
                  </div>
                </div>
              </div>
              <div className="space-y-3 p-5">
                <h3 className="text-xl font-bold">{feature.title}</h3>
                <p className="text-muted-foreground text-sm">
                  {feature.description}
                </p>
                <Button
                  variant="ghost"
                  size="sm"
                  className="group-hover:bg-primary group-hover:text-primary-foreground transition-colors duration-300"
                >
                  Learn more
                  <ArrowRight className="ml-2 h-4 w-4" />
                </Button>
              </div>
            </div>
          ))}
        </div>

        {/* Technical specs */}
        <div className="mt-16 grid grid-cols-1 gap-8 md:grid-cols-2">
          <div className="space-y-6">
            <h3 className="text-2xl font-semibold">Technical specifications</h3>
            <ul className="space-y-4">
              <li className="flex justify-between border-b pb-2">
                <span className="font-medium">Speaker Configuration</span>
                <span className="text-muted-foreground">3-way, 5 drivers</span>
              </li>
              <li className="flex justify-between border-b pb-2">
                <span className="font-medium">Frequency Response</span>
                <span className="text-muted-foreground">28Hz - 22kHz</span>
              </li>
              <li className="flex justify-between border-b pb-2">
                <span className="font-medium">Maximum Output</span>
                <span className="text-muted-foreground">112dB SPL</span>
              </li>
              <li className="flex justify-between border-b pb-2">
                <span className="font-medium">Connectivity</span>
                <span className="text-muted-foreground">
                  Wi-Fi, Bluetooth 5.2, AirPlay, Optical
                </span>
              </li>
              <li className="flex justify-between border-b pb-2">
                <span className="font-medium">Dimensions</span>
                <span className="text-muted-foreground">
                  8.7&quot; x 6.3&quot; x 6.3&quot;
                </span>
              </li>
            </ul>
          </div>
          <div className="space-y-6">
            <h3 className="text-2xl font-semibold">What&apos;s in the box</h3>
            <ul className="space-y-3">
              <li className="flex items-center">
                <div className="bg-primary mr-3 h-2 w-2 rounded-full"></div>
                <span>SoundSphere X1 Speaker</span>
              </li>
              <li className="flex items-center">
                <div className="bg-primary mr-3 h-2 w-2 rounded-full"></div>
                <span>Power Adapter with Country-Specific Plugs</span>
              </li>
              <li className="flex items-center">
                <div className="bg-primary mr-3 h-2 w-2 rounded-full"></div>
                <span>USB-C Charging Cable (1.5m)</span>
              </li>
              <li className="flex items-center">
                <div className="bg-primary mr-3 h-2 w-2 rounded-full"></div>
                <span>Optical Audio Cable (1.5m)</span>
              </li>
              <li className="flex items-center">
                <div className="bg-primary mr-3 h-2 w-2 rounded-full"></div>
                <span>Quick Start Guide</span>
              </li>
              <li className="flex items-center">
                <div className="bg-primary mr-3 h-2 w-2 rounded-full"></div>
                <span>2-Year Warranty Card</span>
              </li>
            </ul>
          </div>
        </div>

        {/* CTA section */}
        <div className="mt-16 flex flex-col items-center justify-center space-y-4 text-center">
          <p className="text-muted-foreground max-w-[600px]">
            Experience immersive audio like never before with our flagship
            SoundSphere X1 speaker, backed by a 2-year warranty and 60-day
            satisfaction guarantee.
          </p>
          <div className="mt-4 flex flex-col gap-4 sm:flex-row">
            <Button size="lg" asChild>
              <a href="#">
                Shop Now
                <ArrowRight className="ml-2 h-4 w-4" />
              </a>
            </Button>
            <Button size="lg" variant="outline" asChild>
              <a href="#">Find a Retailer</a>
            </Button>
          </div>
        </div>

        {/* CSS for hiding scrollbar */}
        <style jsx global>{`
          .scrollbar-hide::-webkit-scrollbar {
            display: none;
          }
        `}</style>
      </div>
    </section>
  );
}
```

### `components/ui/badge.tsx`

```tsx
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"

import { cn } from "@/lib/utils"

const badgeVariants = cva(
  "group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
        secondary:
          "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
        destructive:
          "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
        outline:
          "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
        ghost:
          "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
        link: "text-primary underline-offset-4 hover:underline",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
)

function Badge({
  className,
  variant = "default",
  asChild = false,
  ...props
}: React.ComponentProps<"span"> &
  VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
  const Comp = asChild ? Slot.Root : "span"

  return (
    <Comp
      data-slot="badge"
      data-variant={variant}
      className={cn(badgeVariants({ variant }), className)}
      {...props}
    />
  )
}

export { Badge, badgeVariants }
```

### `components/ui/button.tsx`

```tsx
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"

import { cn } from "@/lib/utils"

const buttonVariants = cva(
  "group/button inline-flex shrink-0 items-center justify-center rounded-md border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/80",
        outline:
          "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
        secondary:
          "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
        ghost:
          "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
        destructive:
          "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
        link: "text-primary underline-offset-4 hover:underline",
      },
      size: {
        default:
          "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
        xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
        sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
        lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
        icon: "size-9",
        "icon-xs":
          "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
        "icon-sm":
          "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md",
        "icon-lg": "size-10",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

function Button({
  className,
  variant = "default",
  size = "default",
  asChild = false,
  ...props
}: React.ComponentProps<"button"> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean
  }) {
  const Comp = asChild ? Slot.Root : "button"

  return (
    <Comp
      data-slot="button"
      data-variant={variant}
      data-size={size}
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    />
  )
}

export { Button, buttonVariants }
```
