Gatsby LightGallery Cloudinary

Donald Boulton

Written by Donald Boulton who lives and works in OKC OK. 

 September 17, 2019   4 min read

Using Cloudinary React Library

Cloudinary is a cloud service that offers a solution to a web application's entire image management pipeline.

Easily upload images to the cloud. Automatically perform smart image resizing, cropping and conversion without installing any complex software. Integrate Facebook or Twitter profile image extraction in a snap, in any dimension and style to match your website’s graphics requirements. Images are seamlessly delivered through a fast CDN, and much much more.

Cloudinary offers comprehensive APIs and administration capabilities and is easy to integrate with any web application, existing or new.

Cloudinary provides URL and HTTP based APIs that can be easily integrated with any Web development framework.

I have used LightGalley in my ASP.NET, Core-2, Jekyll, React and now in my Gatsby site for Image Galleries and iframes to display any kind of html content.

This demo is using Styled Components and mediaQuery in a Styled CSS Grid for the image Cells.

LightGallery has a react SDK for usage in react and vanilla.js for the plugins. The jQuery plugins do not include the .js. as the code blocks below indicate.

LightGallery plugins

import 'lg-autoplay'
import 'lg-autoplay.js'
/* eslint-disable indent */
import React, { Component, Fragment } from 'react'
import { LightgalleryProvider, LightgalleryItem } from 'react-lightgallery'
import axios from 'axios'
import styled from 'styled-components'
import { CloudinaryContext, Transformation, Image } from 'cloudinary-react'
import { Grid, Cell } from 'styled-css-grid'
import { media } from '../../utils/mediaQuery'
import 'lightgallery.js/dist/css/lightgallery.css'

const SectionTitle = styled.h3`
  font-size: 1em;
  margin: 0.67em 0;
    font-size: .85em;
class Gallery extends Component {
  constructor (props) {
    super(props) = React.createRef()
    this.state = {
      gallery: [],
      isOpen: false,
      link: this.href,

  componentDidMount () {
    // Request for images tagged cats

      .then(res => {
        this.setState({ gallery: })
  onLink (event) {
    this.setState({ link: this.href = `

    image/upload/${data.public_id}.jpg` })
  uploadWidget () {
    let _this = this
    // eslint-disable-next-line no-undef
    cloudinary.openUploadWidget({ cloud_name: 'mansbooks', upload_preset:

    'photos-preset', tags: ['cats'], sources: ['local', 'url', 'camera',

    'image_search', 'facebook', 'dropbox', 'instagram'], dropboxAppKey:

    'YOUR KEY', googleApiKey: 'YOUR KEY' },
      // eslint-disable-next-line handle-callback-err
      function (error, result) {
      // Update gallery state with newly uploaded image
          _this.setState({ gallery: })
  render () { 
    return (
          <SectionTitle>Cloudinary LightGallery</SectionTitle>
            <CloudinaryContext cloudName='mansbooks'>
              <Grid columns='repeat(auto-fit,minmax(260px,1fr))' id='hash'>
       => {
                return (
                  <Cell key={data.public_id}>
                    <LightgalleryItem group='group1' src={`


                      <Image publicId={data.public_id} onClick={() =>

                      this.setState({ isOpen: true })}>
                      <div data-sub-html='public_id' />

export default Gallery

The Upload Widget

The upload widget uses Cloudinary CND or the scripts, not a node module.

The Upload Widget Code with advanced styling

import React, { Component } from 'react'
import Helmet from 'react-helmet'
class UploadWidget extends Component {
  uploadWidget () {
      cloud_name: 'mansbooks',
      api_key: 'YOUR KEY',
      api_secret: 'YOUR SECRET',
      username: '',
      upload_preset: 'photos-preset',
      tags: ['cats', 'uploads'],
      sources: ['local', 'url', 'camera', 'image_search', 'facebook', 'dropbox', 'instagram'],
      dropboxAppKey: 'ADD YOUR DROPBOX APP KEY',
      googleApiKey: 'ADD YOUR API KEY',
      showAdvancedOptions: true,
      cropping: true,
      multiple: true,
      image_metadata: 'true',
      defaultSource: 'local',
      styles: {
        palette: {
          window: '#1D1D1D',
          sourceBg: '#000000',
          windowBorder: '#434040',
          tabIcon: '#FFFFFF',
          inactiveTabIcon: '#8E9FBF',
          menuIcons: '#D64000',
          link: '#D64000',
          action: '#9C3204',
          inProgress: '#D64000',
          complete: '#33ff00',
          error: '#EA2727',
          textDark: '#000000',
          textLight: '#FFFFFF',

    function (error, result) {
  render () {
    return (
      <div className='main'>
          <script src='' type='text/javascript' />
        <div className='upload'>
          <button onClick={this.uploadWidget.bind(this)} className='upload-button button'>
            Add Image

export default UploadWidget

The mediaQuery

This use's matchMedia for screen according to window size

import { startCase } from 'lodash'

const min = width => `only screen and (min-width: ${width}em)`
const max = width => `only screen and (max-width: ${width}em)`

const mediaQuery = {
  screens: {
    phone: 30,
    phablet: 40,
    tablet: 50,
    netbook: 60,
    laptop: 70,
    desktop: 100,

for (const key of Object.keys(mediaQuery.screens)) {
  const Key = startCase(key)
  for (const [func, name] of [[min, `min`], [max, `max`]]) {
    // css query
    const query = func(mediaQuery.screens[key])
    mediaQuery[name + Key] = `@media ` + query
    // js query (see window.matchMedia)
    mediaQuery[name + Key + `Js`] = query

export default mediaQuery

Is this a useful post? Please give us a rating!
Is this post Cool? Please Tweet About it!




Heatmaps by Hotjar

Hotjar is the fast and visual way to understand your users..