Display Images
Let’s say you have a bunch of images you want to output into a grid as an image gallery. All your images are in a folder, how would you display them all using Gatsby and its gatsby-image React component?
Install & Configure Plugins
Make sure you have gatsby-image and it’s dependencies installed.
npm install --save gatsby-image
npm install --save gatsby-transformer-sharp
npm install --save gatsby-plugin-sharp
npm install --save gatsby-source-filesystem
Make sure to put them in your Gatsby Project’s gatsby-config.js file.
const path = require(`path`)
module.exports = {
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: path.join(__dirname, `src`, `images`),
},
},
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
],
}
Add Images
Place your images inside a folder, say images/sunsets. Remember gatsby-image does not work with SVG photos.
GraphQL Query
In your React page component where you will be displaying your images (maybe it is the main index.js file) you will need to use a GraphQL query to fetch your images. Don’t forget to GraphQL. It will work without for now, but will be required in the future. import { graphql } from "gatsby"
import React from "react"
import { graphql } from "gatsby"
const sunsets = props => {
const pics = props.data.allFile.edges
return <div></div>
}
export const query = graphql`
{
allFile(filter: { sourceInstanceName: { eq: "sunsets" } }) {
edges {
node {
base
childImageSharp {
fluid {
originalName
...GatsbyImageSharpFluid
}
}
id
}
}
}
}
`
export default sunsets
Map()
I wanted to use the map() function to loop through the data returned from the GraphQL query. The GraphQL query was exported and returns a JS object available from props as “data”. Because the map() function does not work on objects, we need to access the array of photos. Each is a node. So we drill down:
const sunsets = props => {
const pics = props.data.allFile.edges
return (
<>
{pics.map(pic => {
return (
<div key={pic.node.id}>
<p>Hi</p>
</div>
)
})}
</>
)
}
Here I extract the array from the JS object my GraphQL query returned const pics = props.data.allFile.edges
this is not necessary, but looks cleaner than chaining it all in front of the map function. Note that I brought in the “id” property from my query and used it as the “key” prop on the
Warning: Each child in a list should have a unique "key" prop
So our current program loops through all the images in our sunsets folder and returns a
<Img />
tag, which you need to import from “gatsby-image” at the top of your file: import Img from "gatsby-image"
remember it is import React from "react"
import { graphql } from "gatsby"
import Img from "gatsby-image"
const sunsets = props => {
const pics = props.data.allFile.edges
return (
<>
{pics.map(pic => {
return (
<div key={pic.node.id}>
<Img fluid={pic.node.childImageSharp.fluid} alt="somtext" />
</div>
)
})}
</>
)
}
In the return statement inside the tag I drill down and access the image itself using the option to make it fit various screen sizes. The alt text tag is added and set to a static string, we will need to change that later. For now this will display all your photos though.
Alt Text Array
If you have just a small number of images, and don’t plan on changing the order, or letting users add/delete them, you can just use a simple array and map it into the alt text during your map() function.
const itest = props => {
const pics = props.data.allFile.edges
const altText = ["text 1", "text 2", "text 3", "text 4"]
return (
<>
{pics.map((pic, index) => {
return (
<div key={pic.node.id}>
<Img fluid={pic.node.childImageSharp.fluid} alt={altText[index]} />
<p>{altText[index]}</p>
</div>
)
})}
</>
)
}
The second argument of the map function is the current index number of the array (we don’t have to call it index, could easily have called it “blueWhale” instead). So your if the first photo in your src/images/sunsets
is of a kitten, the altText array would be const altText = ["Cute Kitten", "text 2", "text 3", "text 4"]
and so on. Of course if you delete an image in the folder, all photos after that will end up with the incorrect alt text. This method is still fine for small easy to manage lists. Another option is to use an object.
Alt Text Object
With an object you can use a key value pair and easily keep track of all your images alt text, and deleting or adding photos will not change the alt text. For this I used the name of the image file as the object key, and the alt text as the value. My GraphQL query is already pulling in the file name under “originalName” and I store that in the “imgName” variable. Next I slice of the file extension. In my case they all happened to be .png files, but you can write a regex to remove any extension if you have a mix (jpeg, png). I can’t have a ”.” in the object key, so it needs to be removed. Next I use it inside the tag:
<Img alt={altTwo[imgName]} />
and access my altTwo object.
const itest = props => {
const pics = props.data.allFile.edges
const altTwo = {
kittenpic1: "Kitten",
funnbear: "Happy bear",
norway: "Mountains",
}
return (
<div>
{pics.map(pic => {
let imgName = pic.node.childImageSharp.fluid.originalName
imgName = imgName.slice(0, -4)
return (
<div key={pic.node.id}>
<Img fluid={pic.node.childImageSharp.fluid} alt={altTwo[imgName]} />
<p>{altTwo[imgName]}</p>
</div>
)
})}
</div>
)
}
And that is how you display a bunch of images and provide them with alt text.