Joel M. Turner

Illustration

Blog

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.

1import React from 'react';
2import Img from 'gatsby-image';
3
4function Gallery({images = []}) {
5 const wrapperStyles = {
6 display: 'grid',
7 gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
8 gridGap: '1rem';
9 }
10 return (
11 <div style={wrapperStyles}>
12 {nodes.length > 0 && nodes.map(node => <Img fluid={node.localImage.childImageSharp.fluid} />)}
13 </div>
14 )
15}

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 lay 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.

1import React from 'react';
2import Img from 'gatsby-image';
3
4function Gallery({nodes = [], size = 'm'}) {
5
6 function getStylesForSize() {
7 switch (size) {
8 case 's':
9 return {
10 gridTemplateColumns: "repeat(auto-fill, minmax(142px, 1fr))",
11 gridGap: "0.25rem",
12 }
13 case 'm':
14 default:
15 return {
16 gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))",
17 gridGap: "0.5rem",
18 }
19 case 'l':
20 return {
21 gridTemplateColumns: "1fr",
22 gridGap: ".75rem",
23 }
24 }
25 }
26
27 const wrapperStyles = {
28 display: 'grid',
29 ...getStylesForSize()
30 }
31
32 return (
33 <div style={wrapperStyles}>
34 {nodes.length > 0 && nodes.map(node => <Img fluid={node.localImage.childImageSharp.fluid} />)}
35 </div>
36 )
37}

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 passed to the gallery.

1import React from 'react';
2import Img, { FluidObject } from 'gatsby-image';
3
4type GallerySizes = "s" | "m" | "l"
5type GalleryImage = {
6 node: {
7 localImage: {
8 childImageSharp: {
9 fluid: FluidObject;
10 };
11 };
12 id: string;
13 };
14}
15
16type GalleryProps = {
17 imageNodes: GalleryImage[];
18 size?: GallerySizes;
19}
20
21function Gallery({images, size = 'm'}: GalleryProps) {
22
23 function getStylesForSize(): React.CSSProperties {
24 switch (size) {
25 case 's':
26 return {
27 gridTemplateColumns: "repeat(auto-fill, minmax(142px, 1fr))",
28 gridGap: "0.25rem",
29 }
30 case 'm':
31 default:
32 return {
33 gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))",
34 gridGap: "0.5rem",
35 }
36 case 'l':
37 return {
38 gridTemplateColumns: "1fr",
39 gridGap: ".75rem",
40 }
41 }
42 }
43
44 const wrapperStyles: React.CSSProperties = {
45 display: 'grid',
46 ...getStylesForSize(),
47 }
48
49 return (
50 <div style={wrapperStyles}>
51 {nodes.length > 0 && nodes.map(node => <Img fluid={node.localImage.childImageSharp.fluid} />)}
52 </div>
53 )
54}

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

Discuss this article on Twitter