Creating an array of logos in ReactJS with the help of TailwindCSS

After seeing multiple implementations of this feature, I find myself struggling to search for a solution. I can only access the HTML and CSS through inspecting elements, wondering if others are facing the same issue as me.

Typically, we aim to implement this feature to showcase previous clients or portfolio items.

The current implementation works but there is always a stutter every time it loops through the array of images. Below is my React components:


const clients = [
    {
        name: 'google',
        logo: Google,
    },
    // Additional client objects
];

 <div className='overflow-hidden py-8'>
                    <div className='flex animate-left'>
                        <div className=" flex w-max  gap-8 mr-4">
                            {clients.map((client, index) => (
                                <a key={index} href="#" className="flex justify-center items-center shadow-md rounded-xl p-6 w-[10rem] ">
                                    <Image src={client.logo} alt={client.name} width={100} height={100} className="w-full h-full object-contain" />
                                </a>
                            ))}
                        </div>
                        <div className=" flex w-max   gap-8  ">
                            {clients.map((client, index) => (
                                <a key={index} href="#" className="flex justify-center items-center shadow-md rounded-xl p-6 w-[10rem] ">
                                    <Image src={client.logo} alt={client.name} width={100} height={100} className="w-full h-full object-contain" />
                                </a>
                            ))}
                        </div>
                    </div>
                </div>

Here's my Tailwind config :

    extend: {
      animation: {
        'left': 'bannermoveleft 20s linear infinite',
      },
      keyframes: {
        bannermoveleft: {
          '0%': { transform: 'translateX(0)' },
          '100%': { transform: 'translateX(-50%)' },
        }
      },

Answer №1

Utilize the width: max-content property on the scrolling element with w-max to ensure that the -50% value in the transform of bannermoveleft corresponds to the width of one of the cloned items.

Add gap: theme(spacing.8) using gap-8 to the scrolling element and eliminate the mr-4 from the first clone group, ensuring consistent spacing between the clones and items.

Adjust the translateX() function in bannermoveleft by subtracting half of the gap, allowing for a seamless transition until the left edge of the second clone group aligns with the start of the animation loop:

tailwind.config = {
  theme: {
    extend: {
      animation: {
        'left': 'bannermoveleft 5s linear infinite',
      },
      keyframes: {
        bannermoveleft: {
          '0%': { transform: 'translateX(0)' },
          '100%': { transform: 'translateX(calc(-50% - (theme(spacing.8) / 2)))' },
        }
      },
    },
  },
};

const Google = 'https://picsum.photos/100/100';
const Asus = 'https://picsum.photos/100/100?';
const Byu = 'https://picsum.photos/100/100?0';
const Kominfo = 'https://picsum.photos/100/100?1';
const Telkom = 'https://picsum.photos/100/100?2';
const Bi = 'https://picsum.photos/100/100?3';

const clients = [
    {
        name: 'google',
        logo: Google,
    },
    {
        name: 'asus',
        logo: Asus
    },
    {
        name: 'byu',
        logo: Byu,
    },
    {
        name: 'kominfo',
        logo: Kominfo
    },
    {
        name: 'Telkom',
        logo: Telkom,
    },
    {
        name: 'Bank Indonesia',
        logo: Bi,
    },
    // Add more clients as needed
];

function App() {
  return (
    <div className='overflow-hidden py-8'>
      <div className='flex animate-left gap-8 w-max'>
        <div className=" flex w-max gap-8">
          {clients.map((client, index) => (
            <a key={index} href="#" className="flex justify-center items-center shadow-md rounded-xl p-6 w-[10rem] ">
              <img src={client.logo} alt={client.name} width={100} height={100} className="w-full h-full object-contain" />
            </a>
          ))}
        </div>
        <div className=" flex w-max gap-8">
          {clients.map((client, index) => (
            <a key={index} href="#" className="flex justify-center items-center shadow-md rounded-xl p-6 w-[10rem] ">
              <img src={client.logo} alt={client.name} width={100} height={100} className="w-full h-full object-contain" />
            </a>
          ))}
          </div>
        </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('app')).render(<App/>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js" integrity="sha512-8Q6Y9XnTbOE+JNvjBQwJ2H8S+UV4uA6hiRykhdtIyDYZ2TprdNmWOUaKdGzOhyr4dCyk287OejbPvwl7lrfqrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js" integrity="sha512-MOCpqoRoisCTwJ8vQQiciZv0qcpROCidek3GTFS6KTk2+y7munJIlKCVkFCYY+p3ErYFXCjmFjnfTTRSC1OHWQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.tailwindcss.com/3.3.3"></script>

<div id="app"></div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The distance from the edge of my tilted svg icon to the svg artboard

I'm currently working on developing a basic web icon system using SVG sprites. However, I have encountered a spacing issue in my code around one specific icon (between the Smash Magazine icon and the red border). I am trying to figure out how to remov ...

Determine the 'source' attribute value of the image (img) with a dynamically changing Id

Below is the code snippet: <img id="simple_captcha-ad089ff4819" src="/simple_captcha?code=a35401d"> The id of the above img tag changes constantly with each new action. For example, the next id could be "simple_captcha-sfw454sdfs". Therefore, I n ...

AngularJS: Double the power of Ajax. Can you assist me?

ajax was successful twice. Take a look. https://i.sstatic.net/QLdpT.png https://i.sstatic.net/zAbXW.png ...

Initialization of Masonry JS occurs prior to images being fully loaded

I am in the process of creating a website to serve as my portfolio for university applications. Despite my efforts, I am struggling with the javascript aspect and have not been successful in resolving the issue by following similar inquiries. The problem ...

The NodeJS module 'request' is producing symbols instead of expected HTML content

Currently, I am delving into the world of Nodejs and experimenting with web scraping using node.js. My tools of choice are the node modules request and cheerio. However, when I attempt to request a URL, instead of receiving the HTML body, I get strange s ...

The chosen index in the Material Stepper feature is experiencing a malfunction

I've been busy working on a Mat-Stepper, actually two of them. I have a component that contains two ng-templates set up like this: Question: Why is my selected index not functioning as expected? Am I missing something? I know you can define [selected ...

Dynamically enhance the JSON root with additional value

Oh dear, I'm feeling quite perplexed right now. I created a JSON element in the following way: var planet = {"continent": []}; planet.continent.push({name: "Asia", flag: "yes", countries: []}); planet.continent[0].countries.push({name: "Japan", capi ...

Botkit corner flaw

I'm having trouble updating a dependent package included in Botkit. When I run npm install on the package.json provided below, Npm alerts me that the hoek package is vulnerable. I attempted to resolve this by running npm audit fix but it did not wor ...

Choosing an element beneath a table row using a different element as a reference

I'm attempting to identify the checkboxes associated with the link containing delete.jpg. Here's what I've tried so far: <table> <tr class="odd"> <td><input id="cbox1" type="checkbox"></input></td> ...

Transitioning from AngularJS to Angular 2: Exploring Alternatives to $rootScope.$on

Our journey with the AngularJS project has begun on the path towards the modern Angular. The ngMigration utility advised me to eliminate all dependencies on $rootScope since Angular does not have a concept similar to $rootScope. While this is straightforw ...

What is the purpose of utilizing jQuery for retrieving CSS resources?

Upon reviewing the Chrome Dev Tools screenshot, I am puzzled by the fact that my CSS assets are being fetched by jQuery. The CSS sheet is included in the normal way, using a <link rel="stylesheet"> tag in the <head> section, while jQu ...

Is it necessary to use both observer.unobserve and observer.disconnect at the same time?

Is it unnecessary to use both observer.unobserve and observer.disconnect together? Should I just stick with one of them? I have implemented the IntersectionObserver within a useEffect. The code snippet provided is the clean-up function for that useEffect. ...

After selecting an item, the Next UI navbar menu seems to have trouble closing

Having trouble with the navbar menu component not closing when an option is selected from the menu. The menu does open and close successfully within the menu icon. I attempted to use onPress() but it doesn't seem to be working as expected. "use c ...

How to integrate the BackButton component into a React-admin application

I am looking to add a <BackButton /> feature in my use of react-admin. For instance, when viewing a show page for a resource, I want to be able to navigate back to the list page easily. Can someone provide me with guidance on how to achieve this? I ...

The method for connecting the width of a panel to the height of the viewport in Ext Js

I'm looking to automate the adjustment of a panel's height based on the viewport's height using Ext js. Although achievable using listeners, I believe utilizing Ext js variable binding would be more efficient. However, I've encountered ...

Can a CSS class be added to a form_row in Symfony 4 Twig?

Need help with adding a CSS class to the entire form_row in a Symfony 4 twig template! Currently, my code only adds the class to the input tag, but I require it to be added to the parent div container. Here is the current code snippet: {{ form_ ...

In a Vue Application, the static HTML elements are loaded before fetching data

Utilizing VueJS and VueRouter in my application has presented a challenge. The issue lies in the fact that static HTML elements within the Vue Component load before the data is fetched, resulting in empty forms and tables being displayed initially. I have ...

Error not caught: AngularJS module error

Initially, I was hesitant to ask this question, but after struggling for two hours without any success, I've decided to seek some assistance. I'm trying to integrate the ngResource module into my application. Prior to this, everything was functi ...

What is the best way to automatically have the first bar in a column highchart be selected when the page loads?

My highchart consists of a simple column. When I click on any bar in the chart, it gets selected. However, I also want the 1st bar to be selected by default. var chart = $('#container').highcharts(); Upon page load, I have obtained this object. ...

Running res.render in an asynchronous manner within an express application

My goal is to make this router respond asynchronously: var express = require('express'), router = express.Router(); router.get('/', function(req, res, next) { res.render('contact', { titleShown: true, title: & ...