Creating a Responsive Infinite Scrolling Logo Slider with React, Prismic, and CSS

Infinite scrolling carousels are an excellent way to create a dynamic and engaging user experience.

Next.jsFramework
ReactTag
PrismicCMS

Tom McCulloch

Read Time: 5 min

In the world of web development, creating engaging and dynamic user interfaces is key to capturing and maintaining user attention. One popular technique is the infinite scrolling logo slider, often used to showcase partnerships, clients, or featured brands. In this post, we'll walk through how to create a responsive, infinite scrolling logo slider using React, Prismic CMS, and CSS, with a particular focus on ensuring it works well across all device sizes.

The Challenge

The main challenges in creating an infinite scrolling logo slider are:

  1. Achieving a smooth, endless scrolling effect
  2. Ensuring responsiveness across different screen sizes
  3. Preventing layout issues, especially on mobile devices
  4. Managing and updating the logos easily through a content management system

The Solution

Our solution involves a combination of React for component structure, Prismic for content management, and CSS for animation and responsive design. Here's a breakdown of the key elements:

1. Prismic Integration

We'll use Prismic to manage our logos. This allows for easy updates and management of the logos without changing the code. Here's how we set it up:

  1. In Prismic, create a Custom Type for your logos. Let's call it "InfiniteScroller".
  2. Add a Repeatable Zone field named "logo_group" to this Custom Type.
  3. Inside "logo_group", add an Image field for each logo.

2. React Component Structure

We'll create two main components: InfiniteScroller and LogoSlider. The InfiniteScroller component will fetch data from Prismic and pass it to LogoSlider.

Here's the basic structure of InfiniteScroller:

import dynamic from 'next/dynamic';
import { Content } from '@prismicio/client';
import { SliceComponentProps } from '@prismicio/react';
import { ImageField } from '@prismicio/types';

const LogoSlider = dynamic(() => import('./LogoSlider'), { ssr: false });

export type InfiniteScrollerProps = SliceComponentProps<Content.InfiniteScrollerSlice>;

const InfiniteScroller = ({ slice }: InfiniteScrollerProps): JSX.Element => {
  const logos = slice.primary.logo_group.map((item) => item.logo as ImageField);

  return (
    <section className="relative w-full lg:mt-24 mt-2 bg-slate-50 py-12 md:py-16 lg:py-24">
      <div className="w-full px-4 md:w-3/4 lg:w-1/2 mx-auto">
        <h2 className="text-3xl md:text-4xl lg:text-5xl font-bold text-smiths text-center mb-4 md:mb-6">
          Our Ice Cold Partnerships
        </h2>
        <p className="text-sm md:text-base lg:text-lg text-smiths-dark mb-8 md:mb-12 text-center">
          We're proud to serve a diverse range of companies. These logos represent partnerships built on our commitment to excellence in ice supply.
        </p>
      </div>
      <LogoSlider logos={logos} />
    </section>
  );
};

export default InfiniteScroller;

And here's the structure of LogoSlider:

"use client";
import React, { useEffect, useRef } from 'react';
import { ImageField } from '@prismicio/types';

interface LogoSliderProps {
  logos: ImageField[];
}

const LogoSlider: React.FC<LogoSliderProps> = ({ logos }) => {
  // Component logic here
}

export default LogoSlider;

3. Responsive Design with CSS Variables

In the LogoSlider component, we use CSS variables to adjust the slider's properties based on screen size:

useEffect(() => {
  const slider = sliderRef.current;
  if (!slider) return;

  slider.style.setProperty('--n', logos.length.toString());

  const handleResize = () => {
    const viewportWidth = window.innerWidth;
    if (viewportWidth < 640) {
      slider.style.setProperty('--w', '100px');
      slider.style.setProperty('--g', '0.5rem');
      slider.style.setProperty('--d', '15s');
    } else if (viewportWidth < 1024) {
      slider.style.setProperty('--w', '140px');
      slider.style.setProperty('--g', '1rem');
      slider.style.setProperty('--d', '20s');
    } else {
      slider.style.setProperty('--w', '180px');
      slider.style.setProperty('--g', '1.5rem');
      slider.style.setProperty('--d', '25s');
    }
  };

  handleResize();
  window.addEventListener('resize', handleResize);

  return () => window.removeEventListener('resize', handleResize);
}, [logos]);

4. The CSS Magic

The key to making this slider work smoothly lies in the CSS. Here's the crucial part:

.logo-slider-container {
  max-width: 100vw;
  width: 100%;
  overflow: hidden;
  -webkit-mask: linear-gradient(90deg, #0000, #000 10% 90%, #0000);
  mask: linear-gradient(90deg, #0000, #000 10% 90%, #0000);
}

.logo-slider {
  --w: 180px; /* default logo width */
  --g: 1.5rem; /* default gap between logos */
  --d: 25s; /* default duration */
  display: flex;
  width: fit-content;
  animation: scroll var(--d) linear infinite;
}

@keyframes scroll {
  0% { transform: translateX(0); }
  100% { transform: translateX(calc((var(--w) + var(--g)) * var(--n) * -1)); }
}

5. Rendering the Logos

In the render method of our LogoSlider component, we triple the logos array to ensure smooth looping:

const tripleLogos = [...logos, ...logos, ...logos];

return (
  <div className="logo-slider-container">
    <div ref={sliderRef} className="logo-slider flex">
      {tripleLogos.map((logo, index) => (
        <div key={index} className="logo-item flex-shrink-0">
          <img 
            src={logo.url} 
            alt={logo.alt || `Logo ${index + 1}`} 
            className="w-full h-full object-contain"
          />
        </div>
      ))}
    </div>
    {/* CSS styles here */}
  </div>
);

The Result

This implementation creates a smooth, infinite scrolling effect that works across all device sizes. The logos, managed through Prismic, scroll continuously from right to left, creating an engaging visual element on your webpage.

Key Takeaways

  1. Prismic CMS integration allows for easy management and updating of logos.
  2. Use CSS variables for responsive design, adjusting them with JavaScript based on screen size.
  3. The max-width: 100vw; property is crucial for preventing layout issues, especially on mobile.
  4. Tripling the logo array creates a seamless looping effect.
  5. CSS animations can create smooth, performance-efficient scrolling effects.

By combining these techniques with Prismic CMS, you can create a professional-looking, responsive infinite logo slider that enhances the visual appeal of your website while showcasing your partnerships or clients. Plus, the content management aspect allows for easy updates without touching the code.

Remember, the key to great web development is often finding simple, elegant solutions to complex problems, and integrating them with powerful content management systems like Prismic. Happy coding!