Carousel Focus

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

Where the title appears on hover/focus

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 const values = {
  titlePlacement: 'outside',
  items: [
    {
      title: 'Ship faster',
      media: {
        src: 'https://images.unsplash.com/photo-1610611742876-97e4d834d077?q=80&w=1170&auto=format&fit=crop',
        aspect: 'landscape',
      },
    },
    {
      title: 'Performance first',
      media: {
        src: 'https://images.unsplash.com/photo-1688327009265-3e47cdab9dc4?q=80&w=1169&auto=format&fit=crop',
        aspect: 'portrait' as const,
      },
    },
    {
      title: 'Stay in control',
      media: {
        src: 'https://images.unsplash.com/photo-1610210162763-6c4d6da47c8f?q=80&w=1170&auto=format&fit=crop',
        aspect: 'landscape' as const,
      },
    },
    {
      title: 'Built together',
      media: {
        src: 'https://images.unsplash.com/photo-1672917765736-c1c397a5d37f?q=80&w=1170&auto=format&fit=crop',
        aspect: 'portrait' as const,
      },
    },
  ],
} satisfies CarouselFocusProps

export function CarouselFocusExample() {
  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',
        media: {
          src: 'https://images.unsplash.com/photo-1610611742876-97e4d834d077?q=80&w=1170&auto=format&fit=crop',
          aspect: 'landscape' as const,
        },
      },
      {
        title: 'Performance first',
        media: {
          src: 'https://images.unsplash.com/photo-1688327009265-3e47cdab9dc4?q=80&w=1169&auto=format&fit=crop',
          aspect: 'portrait' as const,
        },
      },
      {
        title: 'Stay in control',
        media: {
          src: 'https://images.unsplash.com/photo-1610210162763-6c4d6da47c8f?q=80&w=1170&auto=format&fit=crop',
          aspect: 'landscape' as const,
        },
      },
      {
        title: 'Built together',
        media: {
          src: '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}
    />
  )
}
Need help? Contact me