Carousel Focus

Auto-scrolling carousel that pauses on item hover, dims other items, and reveals an animated title — inside or outside the image.

Loading block…

Implementation

npx shadcn@latest add @flx/carousel-focus

Variations

The block supports a titlePlacement prop that controls where the animated title appears: outside (above the image, default) or inside (overlaid at the bottom of the image with a gradient).

Default

Loading block…

import { CarouselFocus, type CarouselFocusProps } from './carousel-focus'

export function CarouselFocusExample() {
  const values = {
    titlePlacement: 'outside',
    items: [
      {
        title: 'Ship faster',
        image: {
          url: 'https://images.unsplash.com/photo-1610611742876-97e4d834d077?q=80&w=1170&auto=format&fit=crop',
          aspect: 'landscape',
        },
      },
      {
        title: 'Performance first',
        image: {
          url: 'https://images.unsplash.com/photo-1688327009265-3e47cdab9dc4?q=80&w=1169&auto=format&fit=crop',
          aspect: 'portrait' as const,
        },
      },
      {
        title: 'Stay in control',
        image: {
          url: 'https://images.unsplash.com/photo-1610210162763-6c4d6da47c8f?q=80&w=1170&auto=format&fit=crop',
          aspect: 'landscape' as const,
        },
      },
      {
        title: 'Built together',
        image: {
          url: 'https://images.unsplash.com/photo-1672917765736-c1c397a5d37f?q=80&w=1170&auto=format&fit=crop',
          aspect: 'portrait' as const,
        },
      },
    ],
  } satisfies CarouselFocusProps

  return (
    <CarouselFocus
      titlePlacement={values.titlePlacement}
      items={values.items}
    />
  )
}

Title inside the image

When titlePlacement is inside, the title appears overlaid at the bottom of each image with a gradient background.

Loading block…

carousel-focus-title-inside.tsx
import { CarouselFocus, type CarouselFocusProps } from '../carousel-focus'

export function CarouselFocusTitleInside() {
  const values = {
    titlePlacement: 'inside' as const,
    items: [
      {
        title: 'Ship faster',
        image: {
          url: 'https://images.unsplash.com/photo-1610611742876-97e4d834d077?q=80&w=1170&auto=format&fit=crop',
          aspect: 'landscape' as const,
        },
      },
      {
        title: 'Performance first',
        image: {
          url: 'https://images.unsplash.com/photo-1688327009265-3e47cdab9dc4?q=80&w=1169&auto=format&fit=crop',
          aspect: 'portrait' as const,
        },
      },
      {
        title: 'Stay in control',
        image: {
          url: 'https://images.unsplash.com/photo-1610210162763-6c4d6da47c8f?q=80&w=1170&auto=format&fit=crop',
          aspect: 'landscape' as const,
        },
      },
      {
        title: 'Built together',
        image: {
          url: 'https://images.unsplash.com/photo-1672917765736-c1c397a5d37f?q=80&w=1170&auto=format&fit=crop',
          aspect: 'portrait' as const,
        },
      },
    ],
  } satisfies CarouselFocusProps

  return (
    <CarouselFocus
      titlePlacement={values.titlePlacement}
      items={values.items}
    />
  )
}