DEV Community

Cover image for Build a React Gallery With CSS Grid
Joel Turner
Joel Turner

Posted on • Originally published at joelmturner.com on

Build a React Gallery With CSS Grid

CSS Grid is super powerful and can be used to create some creative layouts which makes it a great way to create galleries. In this guide, we’re going to use a simple grid that keeps the images the same size.

This will be a quick view of CSS Grid. If you would like to know more I highly recommend the CSS Grid Course (free) from Wes Bos.

Here are the requirements for this component:

  • Accepts an array of images (using Gatsby Image)
  • Needs to respond to different size screens (using minmax)
  • Takes a size prop of s, m, or l

Cool, let’s start building it out. We’re building this one based on a query for Gatsby Image. You can set this up for any image component or element that you may be using.

import React from 'react';
import Img from 'gatsby-image';

function Gallery({images = []}) {
  const wrapperStyles = {
    display: 'grid',
    gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
    gridGap: '1rem';
  }
  return (
    <div style={wrapperStyles}>
      {nodes.length > 0 && nodes.map(node => <Img fluid={node.localImage.childImageSharp.fluid} />)}
    </div>
  )
}

The wrapper styles will give the children their sizes based on the grid and row declarations. In this case, we have gridTemplateColumns: ‘repeat(auto-fill, minmax(300px, 1fr))’ Which tells the images to be laid out in as many columns that will fit based on a minimum width of 300px and a maximum of 1fr. The gridGap tells them to have a gap of 1rem between images.

We’ll add a function that can handle the different sizing from the size prop and pass these into the wrapper styles.

import React from 'react';
import Img from 'gatsby-image';

function Gallery({nodes = [], size = 'm'}) {

  function getStylesForSize() {
    switch (size) {
      case 's': 
        return {
          gridTemplateColumns: "repeat(auto-fill, minmax(142px, 1fr))",
          gridGap: "0.25rem",
        }
      case 'm':
      default:
        return {
          gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))",
          gridGap: "0.5rem",
        }
      case 'l': 
        return {
          gridTemplateColumns: "1fr",
          gridGap: ".75rem",
        }
    }
  }

  const wrapperStyles = {
    display: 'grid',
    ...getStylesForSize()
  }

  return (
    <div style={wrapperStyles}>
      {nodes.length > 0 && nodes.map(node => <Img fluid={node.localImage.childImageSharp.fluid} />)}
    </div>
  )
}

We can now pass our size changes to the gallery component. Cool!

TypeScript

Now, let’s type it. This will help us and others know what we shape we need to be passed to the gallery.

import React from 'react';
import Img, { FluidObject } from 'gatsby-image';

type GallerySizes = "s" | "m" | "l"
type GalleryImage = {
  node: {
    localImage: {
      childImageSharp: {
        fluid: FluidObject;
      };
    };
    id: string;
  };
}

type GalleryProps = {
  imageNodes: GalleryImage[];
  size?: GallerySizes;
}

function Gallery({images, size = 'm'}: GalleryProps) {

  function getStylesForSize(): React.CSSProperties {
    switch (size) {
      case 's': 
        return {
          gridTemplateColumns: "repeat(auto-fill, minmax(142px, 1fr))",
          gridGap: "0.25rem",
        }
      case 'm':
      default:
        return {
          gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))",
          gridGap: "0.5rem",
        }
      case 'l': 
        return {
          gridTemplateColumns: "1fr",
          gridGap: ".75rem",
        }
    }
  }

  const wrapperStyles: React.CSSProperties = {
    display: 'grid',
    ...getStylesForSize(),
  }

  return (
    <div style={wrapperStyles}>
      {nodes.length > 0 && nodes.map(node => <Img fluid {node.localImage.childImageSharp.fluid} />)}
    </div>
  )
}

Nice! Now we have a functioning gallery component that can change sizes. You can see my implementation of this on my illustration page.

Discussion (0)