0

I have array of object ImageKist where I would like to show alternate image with different heights using grid or flex as shown below:enter image description here

How can I achieve above pattern using grid or flex?

Install styled-component as follow: npm install --save styled-components

Current result is as below where images should come from left to right where I have used grid but its fine if we get the desired result with flex. enter image description here

Below is my code with alternate images:

import styled from "styled-components";
import React from "react";

const App = () => {
const imageList = [
{
  id: "1",
  url: "https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
},
{
  id: "2",
  url: "https://images.unsplash.com/photo-1572276596237-5db2c3e16c5d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
},
{
  id: "3",
  url: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1353&q=80",
},
{
  id: "4",
  url: "https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80",
},
{
  id: "5",
  url: "https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80",
},
{
  id: "6",
  url: "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883334/person-1_rfzshl.jpg",
},
{
  id: "7",
  url: "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883409/person-2_np9x5l.jpg",
},
{
  id: "8",
  url: "https://res.cloudinary.com/diqqf3eq2/image/upload/v1586883417/person-3_ipa0mj.jpg",
},
];

return (
<Wrapper>
  {imageList.map((image: any, index) => (
    <>
      {index % 2 === 0 ? (
        <ImageWrapper key={image.id}>
          <ImageStyled src={image.url} alt={image.url} />
          <H4Styled>{image.id}</H4Styled>
        </ImageWrapper>
      ) : (
        <ImageWrapper1 key={image.id}>
          <ImageStyled src={image.url} alt={image.url} />
          <H4Styled>{image.id}</H4Styled>
        </ImageWrapper1>
      )}
    </>
  ))}
</Wrapper>
);
};

export default App;

const Wrapper = styled.div`
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 80px;
gap: 30px;
`;

const ImageWrapper = styled.div`
overflow: hidden;
position: relative;
grid-row: span 2;
`;

const ImageWrapper1 = styled.div`
overflow: hidden;
position: relative;
grid-row: span 3;
`;

const ImageStyled = styled.img`
min-width: 100%;
height: 100%;
border-radius: 20px;
`;

const H4Styled = styled.h4`
position: absolute;
top: 16px;
color: white;
`;
MeAtWork
  • 59
  • 7

1 Answers1

1

Update

Only quickly tested but this seems to work for me in TypeScript:

interface ImageWrapperProps {
  index: number;
}

And apply the interface to the component using index as prop:

const ImageWrapper = styled.div`
  overflow: hidden;
  position: relative;
  border-radius: 20px;
  grid-row: ${({ index }: ImageWrapperProps) =>
    (index + 1) % 2 === 0 ? 'span 3' : 'span 2'};
  grid-column: ${({ index }: ImageWrapperProps) =>
    (index + 2) % 6 === 0 ? '2' : 'auto'};
`;

It probably depends on configurations, so if it does not work perhaps also reference some suggestions to use TypeScriptt with styled-components from this question.

Also if not done yet perhaps try install @types/styled-components in the project:

npm install @types/styled-components

Original

It seems that the props of styled-components can be used to simplify the logic and also manage the placement of images based on the index.

The below example pass the index as prop to ImageWrapper and change the grid-row and grid-column based on index as a condition, so there is no need to define 2 components for it.

The current condition works for a 3 column image list, but it can be adjusted in the styles to fit other layout, if needed.

Simplified live demo of example: stackblitz

Perhaps try:

const Wrapper = styled.div`
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 80px;
gap: 30px;
grid-auto-flow: row dense;
`;

//  Use prop here to change style by condition
const ImageWrapper = styled.div`
overflow: hidden;
position: relative;
border-radius: 20px;
grid-row: ${({ index }) => ((index + 1) % 2 === 0 ? 'span 3' : 'span 2')};
grid-column: ${({ index }) => ((index + 2) % 6 === 0 ? '2' : 'auto')};
`;

const ImageStyled = styled.img`
width: 100%;
height: 100%;
object-fit: cover;
`;

const H4Styled = styled.h4`
position: absolute;
top: 16px;
color: white;
`;

And in the output:

<Wrapper>
  {imageList.map((image, index) => (
    <ImageWrapper key={image.id} index={index}>
      <ImageStyled src={image.url} alt={image.url} />
      <H4Styled>{image.id}</H4Styled>
    </ImageWrapper>
  ))}
</Wrapper>
John Li
  • 6,976
  • 3
  • 3
  • 27
  • @TruptiGaonkar My bad, did not notice that TypeScript is also needed. I updated the answer with what works for me in TypeScript, although it might also depends on config but hopefully it could help. Perhaps also try some other methods from this [question](https://stackoverflow.com/q/47077210/20436957). – John Li Dec 28 '22 at 10:19