All examples consist of images with differing sizes and aspect ratios shuffled on every page load. Resizing the browser window will adjust the gallery layout seamlessly.
Demo
Installation
Using npm:
npm install --save react-grid-gallery
Quick (and dirty) Start
import React from 'react';
import { render } from 'react-dom';
import Gallery from 'react-grid-gallery';
const IMAGES =
[{
src: "https://c2.staticflickr.com/9/8817/28973449265_07e3aa5d2e_b.jpg",
thumbnail: "https://c2.staticflickr.com/9/8817/28973449265_07e3aa5d2e_n.jpg",
thumbnailWidth: 320,
thumbnailHeight: 174,
isSelected: true,
caption: "After Rain (Jeshu John - designerspics.com)"
},
{
src: "https://c2.staticflickr.com/9/8356/28897120681_3b2c0f43e0_b.jpg",
thumbnail: "https://c2.staticflickr.com/9/8356/28897120681_3b2c0f43e0_n.jpg",
thumbnailWidth: 320,
thumbnailHeight: 212,
tags: [{value: "Ocean", title: "Ocean"}, {value: "People", title: "People"}],
caption: "Boats (Jeshu John - designerspics.com)"
},
{
src: "https://c4.staticflickr.com/9/8887/28897124891_98c4fdd82b_b.jpg",
thumbnail: "https://c4.staticflickr.com/9/8887/28897124891_98c4fdd82b_n.jpg",
thumbnailWidth: 320,
thumbnailHeight: 212
}]
render(
<Gallery images={IMAGES}/>,
document.getElementById('example-0')
);
Image Options
Property | Type | Default | Description |
---|---|---|---|
src | string | undefined | Required. A string referring to any valid image resource (file, url, etc). |
thumbnail | string | undefined | Required. A string referring to any valid image resource (file, url, etc). |
thumbnailWidth | number | undefined | Required. Width of the thumbnail image. |
thumbnailHeight | number | undefined | Required. Height of the thumbnail image. |
tags | array | undefined | Optional. An array of objects containing tag attributes (value and title). e.g. {value: "foo", title: "bar"} |
isSelected | bool | undefined | Optional. The selected state of the image. |
caption | string | undefined | Optional. Image caption. |
srcset | array | undefined | Optional. Array of srcsets for lightbox. |
Gallery Options
Property | Type | Default | Description |
---|---|---|---|
images | array | undefined | Required. An array of objects containing image properties (see Image Options above). |
enableImageSelection | bool | true | Optional. Allow images to be selectable. Setting this option to false whilst supplying images with isSelected: true will result in those images being permanently selected. |
onSelectImage | func | undefined | Optional. Function to execute when an image is selected. Optional args: index (index of selected image in images array), image (the selected image). This function is only executable when enableImageSelection: true . |
rowHeight | number | 180 | Optional. The height of each row in the gallery. |
margin | number | 2 | Optional. The margin around each image in the gallery. |
enableLightbox | bool | true | Optional. Enable lightbox display of full size image when thumbnail clicked. |
onClickThumbnail | func | openLightbox | Optional. Function to execute when gallery thumbnail clicked. Overrides openLightbox. |
Lightbox Options
NOTE: these options are passed inside the Gallery tag.
e.g.
<Gallery images={IMAGES} backdropClosesModal={true}/>
Property | Type | Default | Description |
---|---|---|---|
backdropClosesModal | bool | false | Optional. Allow users to exit the lightbox by clicking the backdrop. |
currentImage | number | 0 | Optional. The index of the image to display initially (only relevant when used in conjunction with isOpen: true property). |
preloadNextImage | bool | true | Optional. Based on the direction the user is navigating, preload the next available image. |
customControls | array | undefined | Optional. An array of elements to display as custom controls on the top of lightbox. |
enableKeyboardInput | bool | true | Optional. Supports keyboard input - esc , arrow left , and arrow right . |
imageCountSeparator | string | ' of ' | Optional. Customize separator in the image count. |
isOpen | bool | false | Optional. Whether or not the lightbox is displayed when gallery first rendered (can be used in conjunction with currentImage property, otherwise the first image will be diplayed). |
showCloseButton | bool | true | Optional. Display a close "X" button in top right corner. |
showImageCount | bool | true | Optional. Display image index, e.g., "3 of 20". |
onClickImage | func | onClickImage | Optional. Function to execute when lightbox image clicked. Overrides internal implementation of onClickImage. |
onClickPrev | func | onClickPrev | Optional. Function to execute when lightbox left arrow clicked. Overrides internal implementation of onClickPrev. |
onClickNext | func | onClickNext | Optional. Function to execute when lightbox right arrow clicked. Overrides internal implementation of onClickNext. |
General Notes
As the inspiration for this component comes from Google Photos, very small thumbnails may not be the most aesthetically pleasing due to the border size applied when selected. A sensible rowHeight default of 180px has been chosen, but rowHeights down to 100px are still reasonable.
Gallery width is determined by the containing element.
Image Options:
thumbnail
can point to the same resource assrc
, bearing in mind the resultant data size of the gallery and page load cost. Thumbnails of whatever size will be scaled to matchrowHeight
.
- If you don't know your
thumbnailWidth
andthumbnailHeight
values, you can find these out using any number of javascript hacks, bearing in mind the load penalty associated with these methods.
License
React Grid Gallery is free to use for personal and commercial projects under the MIT License. Attribution is not required, but appreciated.
Acknowledgements
Visual design inspired by Google Photos.
Thumbnail viewport implementation inspired by GPlusGallery by Florian Maul.
Backend lightbox functionality via React Images by jossmac.
The following gallery functions were obtained from jossmac from his React Images example and as such the copyright remains with him: closeLightbox, gotoNext, gotoPrevious, handleClickImage, openLightbox.
Demo stock photos:
Examples
Pre-selected Images
import React from 'react'; import ReactDOM from 'react-dom'; import Gallery from 'react-grid-gallery'; class Demo1 extends React.Component { constructor(props){ super(props); this.state = { images: this.props.images }; this.onSelectImage = this.onSelectImage.bind(this); } onSelectImage (index, image) { var images = this.state.images.slice(); var img = images[index]; if(img.hasOwnProperty("isSelected")) img.isSelected = !img.isSelected; else img.isSelected = true; this.setState({ images: images }); } render () { return ( <div style={{ display: "block", minHeight: "1px", width: "100%", border: "1px solid #ddd", overflow: "auto"}}> <Gallery images={this.state.images} onSelectImage={this.onSelectImage}/> </div> ); } } Demo1.propTypes = { images: React.PropTypes.arrayOf( React.PropTypes.shape({ src: React.PropTypes.string.isRequired, thumbnail: React.PropTypes.string.isRequired, srcset: React.PropTypes.array, caption: React.PropTypes.string, thumbnailWidth: React.PropTypes.number.isRequired, thumbnailHeight: React.PropTypes.number.isRequired, isSelected: React.PropTypes.bool }) ).isRequired }; Demo1.defaultProps = { images: shuffleArray([ { src: "https://c5.staticflickr.com/9/8768/28941110956_b05ab588c1_b.jpg", thumbnail: "https://c5.staticflickr.com/9/8768/28941110956_b05ab588c1_n.jpg", thumbnailWidth: 240, thumbnailHeight: 320, caption: "8H (gratisography.com)" }, { src: "https://c3.staticflickr.com/9/8583/28354353794_9f2d08d8c0_b.jpg", thumbnail: "https://c3.staticflickr.com/9/8583/28354353794_9f2d08d8c0_n.jpg", thumbnailWidth: 320, thumbnailHeight: 190, caption: "286H (gratisography.com)" }, { src: "https://c7.staticflickr.com/9/8569/28941134686_d57273d933_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8569/28941134686_d57273d933_n.jpg", thumbnailWidth: 320, thumbnailHeight: 148, caption: "315H (gratisography.com)" }, { src: "https://c6.staticflickr.com/9/8342/28897193381_800db6419e_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8342/28897193381_800db6419e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, isSelected: true, caption: "201H (gratisography.com)" }, { src: "https://c2.staticflickr.com/9/8239/28897202241_1497bec71a_b.jpg", thumbnail: "https://c2.staticflickr.com/9/8239/28897202241_1497bec71a_n.jpg", thumbnailWidth: 248, thumbnailHeight: 320, caption: "Big Ben (Tom Eversley - isorepublic.com)" }, { src: "https://c7.staticflickr.com/9/8785/28687743710_3580fcb5f0_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8785/28687743710_3580fcb5f0_n.jpg", thumbnailWidth: 320, thumbnailHeight: 113, isSelected: true, caption: "Red Zone - Paris (Tom Eversley - isorepublic.com)" }, { src: "https://c6.staticflickr.com/9/8520/28357073053_cafcb3da6f_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8520/28357073053_cafcb3da6f_n.jpg", thumbnailWidth: 313, thumbnailHeight: 320, caption: "Wood Glass (Tom Eversley - isorepublic.com)" }, { src: "https://c8.staticflickr.com/9/8104/28973555735_ae7c208970_b.jpg", thumbnail: "https://c8.staticflickr.com/9/8104/28973555735_ae7c208970_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, isSelected: true, caption: "Flower Interior Macro (Tom Eversley - isorepublic.com)" } ]) }; ReactDOM.render(<Demo1 />, document.getElementById('demo1'));
Pemanently selected Images
import React from 'react'; import ReactDOM from 'react-dom'; import Gallery from 'react-grid-gallery'; class Demo2 extends React.Component { constructor(props){ super(props); this.state = { images: this.props.images }; } render () { return ( <div style={{ display: "block", minHeight: "1px", width: "100%", border: "1px solid #ddd", overflow: "auto"}}> <Gallery images={this.state.images} enableImageSelection={false}/> </div> ); } } Demo2.propTypes = { images: React.PropTypes.arrayOf( React.PropTypes.shape({ src: React.PropTypes.string.isRequired, thumbnail: React.PropTypes.string.isRequired, srcset: React.PropTypes.array, caption: React.PropTypes.string, thumbnailWidth: React.PropTypes.number.isRequired, thumbnailHeight: React.PropTypes.number.isRequired, isSelected: React.PropTypes.bool }) ).isRequired }; Demo2.defaultProps = { images: shuffleArray([ { src: "https://c5.staticflickr.com/9/8768/28941110956_b05ab588c1_b.jpg", thumbnail: "https://c5.staticflickr.com/9/8768/28941110956_b05ab588c1_n.jpg", thumbnailWidth: 240, thumbnailHeight: 320, isSelected: true, caption: "8H (gratisography.com)" }, { src: "https://c3.staticflickr.com/9/8583/28354353794_9f2d08d8c0_b.jpg", thumbnail: "https://c3.staticflickr.com/9/8583/28354353794_9f2d08d8c0_n.jpg", thumbnailWidth: 320, thumbnailHeight: 190, caption: "286H (gratisography.com)" }, { src: "https://c7.staticflickr.com/9/8569/28941134686_d57273d933_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8569/28941134686_d57273d933_n.jpg", thumbnailWidth: 320, thumbnailHeight: 148, isSelected: true, caption: "315H (gratisography.com)" }, { src: "https://c6.staticflickr.com/9/8342/28897193381_800db6419e_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8342/28897193381_800db6419e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "201H (gratisography.com)" }, { src: "https://c2.staticflickr.com/9/8239/28897202241_1497bec71a_b.jpg", thumbnail: "https://c2.staticflickr.com/9/8239/28897202241_1497bec71a_n.jpg", thumbnailWidth: 248, thumbnailHeight: 320, caption: "Big Ben (Tom Eversley - isorepublic.com)" }, { src: "https://c7.staticflickr.com/9/8785/28687743710_3580fcb5f0_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8785/28687743710_3580fcb5f0_n.jpg", thumbnailWidth: 320, thumbnailHeight: 113, caption: "Red Zone - Paris (Tom Eversley - isorepublic.com)" }, { src: "https://c6.staticflickr.com/9/8520/28357073053_cafcb3da6f_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8520/28357073053_cafcb3da6f_n.jpg", thumbnailWidth: 313, thumbnailHeight: 320, isSelected: true, caption: "Wood Glass (Tom Eversley - isorepublic.com)" }, { src: "https://c8.staticflickr.com/9/8104/28973555735_ae7c208970_b.jpg", thumbnail: "https://c8.staticflickr.com/9/8104/28973555735_ae7c208970_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Flower Interior Macro (Tom Eversley - isorepublic.com)" } ]) }; ReactDOM.render(<Demo2 />, document.getElementById('demo2'));
Simple Gallery (Lightbox and Image Selection Disabled)
import React from 'react'; import ReactDOM from 'react-dom'; import Gallery from 'react-grid-gallery'; class Demo3 extends React.Component { constructor(props){ super(props); this.state = { images: this.props.images }; } render () { return ( <div style={{ display: "block", minHeight: "1px", width: "100%", border: "1px solid #ddd", overflow: "auto"}}> <Gallery images={this.state.images} enableLightbox={false} enableImageSelection={false}/> </div> ); } } Demo3.propTypes = { images: React.PropTypes.arrayOf( React.PropTypes.shape({ src: React.PropTypes.string.isRequired, thumbnail: React.PropTypes.string.isRequired, srcset: React.PropTypes.array, caption: React.PropTypes.string, thumbnailWidth: React.PropTypes.number.isRequired, thumbnailHeight: React.PropTypes.number.isRequired }) ).isRequired }; Demo3.defaultProps = { images: shuffleArray([ { src: "https://c2.staticflickr.com/9/8817/28973449265_07e3aa5d2e_b.jpg", thumbnail: "https://c2.staticflickr.com/9/8817/28973449265_07e3aa5d2e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 174, caption: "After Rain (Jeshu John - designerspics.com)" }, { src: "https://c6.staticflickr.com/9/8890/28897154101_a8f55be225_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8890/28897154101_a8f55be225_n.jpg", thumbnailWidth: 320, thumbnailHeight: 183, caption: "37H (gratispgraphy.com)" }, { src: "https://c7.staticflickr.com/9/8106/28941228886_86d1450016_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8106/28941228886_86d1450016_n.jpg", thumbnailWidth: 271, thumbnailHeight: 320, caption: "Orange Macro (Tom Eversley - isorepublic.com)" }, { src: "https://c6.staticflickr.com/9/8342/28897193381_800db6419e_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8342/28897193381_800db6419e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "201H (gratisography.com)" }, { src: "https://c8.staticflickr.com/9/8104/28973555735_ae7c208970_b.jpg", thumbnail: "https://c8.staticflickr.com/9/8104/28973555735_ae7c208970_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Flower Interior Macro (Tom Eversley - isorepublic.com)" }, { src: "https://c1.staticflickr.com/9/8707/28868704912_cba5c6600e_b.jpg", thumbnail: "https://c1.staticflickr.com/9/8707/28868704912_cba5c6600e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Man on BMX (Tom Eversley - isorepublic.com)" }, { src: "https://c4.staticflickr.com/9/8578/28357117603_97a8233cf5_b.jpg", thumbnail: "https://c4.staticflickr.com/9/8578/28357117603_97a8233cf5_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Ropeman - Thailand (Tom Eversley - isorepublic.com)" }, { src: "https://c1.staticflickr.com/9/8056/28354485944_148d6a5fc1_b.jpg", thumbnail: "https://c1.staticflickr.com/9/8056/28354485944_148d6a5fc1_n.jpg", thumbnailWidth: 257, thumbnailHeight: 320, caption: "A photo by 贝莉儿 NG. (unsplash.com)" } ]) }; ReactDOM.render(<Demo3 />, document.getElementById('demo3'));
Code Sample (from demo at the top of the page)
import React from 'react'; import ReactDOM from 'react-dom'; import Gallery from 'react-grid-gallery'; import CheckButton from '../src/CheckButton'; class Demo0 extends React.Component { constructor(props){ super(props); this.state = { images: this.props.images, selectAllChecked: false }; this.onSelectImage = this.onSelectImage.bind(this); this.getSelectedImages = this.getSelectedImages.bind(this); this.onClickSelectAll = this.onClickSelectAll.bind(this); } allImagesSelected (images){ var f = images.filter( function (img) { return img.isSelected == true; } ); return f.length == images.length; } onSelectImage (index, image) { var images = this.state.images.slice(); var img = images[index]; if(img.hasOwnProperty("isSelected")) img.isSelected = !img.isSelected; else img.isSelected = true; this.setState({ images: images }); if(this.allImagesSelected(images)){ this.setState({ selectAllChecked: true }); } else { this.setState({ selectAllChecked: false }); } } getSelectedImages () { var selected = []; for(var i = 0; i < this.state.images.length; i++) if(this.state.images[i].isSelected == true) selected.push(i); return selected; } onClickSelectAll () { var selectAllChecked = !this.state.selectAllChecked; this.setState({ selectAllChecked: selectAllChecked }); var images = this.state.images.slice(); if(selectAllChecked){ for(var i = 0; i < this.state.images.length; i++) images[i].isSelected = true; } else { for(var i = 0; i < this.state.images.length; i++) images[i].isSelected = false; } this.setState({ images: images }); } render () { return ( <div> <CheckButton index={0} isSelected={this.state.selectAllChecked} onClick={this.onClickSelectAll} parentHover={true} color={"rgba(0,0,0,0.54)"} selectedColor={"#4285f4"} hoverColor={"rgba(0,0,0,0.54)"}/> <div style={{ height: "36px", display: "flex", alignItems: "center" }}> select all </div> <div style={{ padding: "2px", color: "#666" }}>Selected images: {this.getSelectedImages().toString()}</div> <div style={{ display: "block", minHeight: "1px", width: "100%", border: "1px solid #ddd", overflow: "auto"}}> <Gallery images={this.state.images} onSelectImage={this.onSelectImage}/> </div> </div> ); } } Demo0.propTypes = { images: React.PropTypes.arrayOf( React.PropTypes.shape({ src: React.PropTypes.string.isRequired, thumbnail: React.PropTypes.string.isRequired, srcset: React.PropTypes.array, caption: React.PropTypes.string, thumbnailWidth: React.PropTypes.number.isRequired, thumbnailHeight: React.PropTypes.number.isRequired, isSelected: React.PropTypes.bool }) ).isRequired }; Demo0.defaultProps = { images: shuffleArray([ { src: "https://c2.staticflickr.com/9/8817/28973449265_07e3aa5d2e_b.jpg", thumbnail: "https://c2.staticflickr.com/9/8817/28973449265_07e3aa5d2e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 174, tags: [{value: "Nature", title: "Nature"}, {value: "Flora", title: "Flora"}], caption: "After Rain (Jeshu John - designerspics.com)" }, { src: "https://c2.staticflickr.com/9/8356/28897120681_3b2c0f43e0_b.jpg", thumbnail: "https://c2.staticflickr.com/9/8356/28897120681_3b2c0f43e0_n.jpg", thumbnailWidth: 320, thumbnailHeight: 212, caption: "Boats (Jeshu John - designerspics.com)" }, { src: "https://c4.staticflickr.com/9/8887/28897124891_98c4fdd82b_b.jpg", thumbnail: "https://c4.staticflickr.com/9/8887/28897124891_98c4fdd82b_n.jpg", thumbnailWidth: 320, thumbnailHeight: 212, caption: "Color Pencils (Jeshu John - designerspics.com)" }, { src: "https://c7.staticflickr.com/9/8546/28354329294_bb45ba31fa_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8546/28354329294_bb45ba31fa_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Red Apples with other Red Fruit (foodiesfeed.com)" }, { src: "https://c6.staticflickr.com/9/8890/28897154101_a8f55be225_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8890/28897154101_a8f55be225_n.jpg", thumbnailWidth: 320, thumbnailHeight: 183, caption: "37H (gratispgraphy.com)" }, { src: "https://c5.staticflickr.com/9/8768/28941110956_b05ab588c1_b.jpg", thumbnail: "https://c5.staticflickr.com/9/8768/28941110956_b05ab588c1_n.jpg", thumbnailWidth: 240, thumbnailHeight: 320, tags: [{value: "Nature", title: "Nature"}], caption: "8H (gratisography.com)" }, { src: "https://c3.staticflickr.com/9/8583/28354353794_9f2d08d8c0_b.jpg", thumbnail: "https://c3.staticflickr.com/9/8583/28354353794_9f2d08d8c0_n.jpg", thumbnailWidth: 320, thumbnailHeight: 190, caption: "286H (gratisography.com)" }, { src: "https://c7.staticflickr.com/9/8569/28941134686_d57273d933_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8569/28941134686_d57273d933_n.jpg", thumbnailWidth: 320, thumbnailHeight: 148, tags: [{value: "People", title: "People"}], caption: "315H (gratisography.com)" }, { src: "https://c6.staticflickr.com/9/8342/28897193381_800db6419e_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8342/28897193381_800db6419e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "201H (gratisography.com)" }, { src: "https://c2.staticflickr.com/9/8239/28897202241_1497bec71a_b.jpg", thumbnail: "https://c2.staticflickr.com/9/8239/28897202241_1497bec71a_n.jpg", thumbnailWidth: 248, thumbnailHeight: 320, caption: "Big Ben (Tom Eversley - isorepublic.com)" }, { src: "https://c7.staticflickr.com/9/8785/28687743710_3580fcb5f0_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8785/28687743710_3580fcb5f0_n.jpg", thumbnailWidth: 320, thumbnailHeight: 113, tags: [{value: "People", title: "People"}], caption: "Red Zone - Paris (Tom Eversley - isorepublic.com)" }, { src: "https://c6.staticflickr.com/9/8520/28357073053_cafcb3da6f_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8520/28357073053_cafcb3da6f_n.jpg", thumbnailWidth: 313, thumbnailHeight: 320, caption: "Wood Glass (Tom Eversley - isorepublic.com)" }, { src: "https://c8.staticflickr.com/9/8104/28973555735_ae7c208970_b.jpg", thumbnail: "https://c8.staticflickr.com/9/8104/28973555735_ae7c208970_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Flower Interior Macro (Tom Eversley - isorepublic.com)" }, { src: "https://c4.staticflickr.com/9/8562/28897228731_ff4447ef5f_b.jpg", thumbnail: "https://c4.staticflickr.com/9/8562/28897228731_ff4447ef5f_n.jpg", thumbnailWidth: 320, thumbnailHeight: 194, caption: "Old Barn (Tom Eversley - isorepublic.com)" }, { src: "https://c2.staticflickr.com/8/7577/28973580825_d8f541ba3f_b.jpg", thumbnail: "https://c2.staticflickr.com/8/7577/28973580825_d8f541ba3f_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Cosmos Flower Macro (Tom Eversley - isorepublic.com)" }, { src: "https://c7.staticflickr.com/9/8106/28941228886_86d1450016_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8106/28941228886_86d1450016_n.jpg", thumbnailWidth: 271, thumbnailHeight: 320, caption: "Orange Macro (Tom Eversley - isorepublic.com)" }, { src: "https://c1.staticflickr.com/9/8330/28941240416_71d2a7af8e_b.jpg", thumbnail: "https://c1.staticflickr.com/9/8330/28941240416_71d2a7af8e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, tags: [{value: "Nature", title: "Nature"}, {value: "People", title: "People"}], caption: "Surfer Sunset (Tom Eversley - isorepublic.com)" }, { src: "https://c1.staticflickr.com/9/8707/28868704912_cba5c6600e_b.jpg", thumbnail: "https://c1.staticflickr.com/9/8707/28868704912_cba5c6600e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, tags: [{value: "People", title: "People"}, {value: "Sport", title: "Sport"}], caption: "Man on BMX (Tom Eversley - isorepublic.com)" }, { src: "https://c4.staticflickr.com/9/8578/28357117603_97a8233cf5_b.jpg", thumbnail: "https://c4.staticflickr.com/9/8578/28357117603_97a8233cf5_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Ropeman - Thailand (Tom Eversley - isorepublic.com)" }, { src: "https://c4.staticflickr.com/8/7476/28973628875_069e938525_b.jpg", thumbnail: "https://c4.staticflickr.com/8/7476/28973628875_069e938525_n.jpg", thumbnailWidth: 320, thumbnailHeight: 213, caption: "Time to Think (Tom Eversley - isorepublic.com)" }, { src: "https://c6.staticflickr.com/9/8593/28357129133_f04c73bf1e_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8593/28357129133_f04c73bf1e_n.jpg", thumbnailWidth: 320, thumbnailHeight: 179, tags: [{value: "Nature", title: "Nature"}, {value: "Fauna", title: "Fauna"}], caption: "Untitled (Jan Vasek - jeshoots.com)" }, { src: "https://c6.staticflickr.com/9/8893/28897116141_641b88e342_b.jpg", thumbnail: "https://c6.staticflickr.com/9/8893/28897116141_641b88e342_n.jpg", thumbnailWidth: 320, thumbnailHeight: 215, tags: [{value: "People", title: "People"}], caption: "Untitled (moveast.me)" }, { src: "https://c1.staticflickr.com/9/8056/28354485944_148d6a5fc1_b.jpg", thumbnail: "https://c1.staticflickr.com/9/8056/28354485944_148d6a5fc1_n.jpg", thumbnailWidth: 257, thumbnailHeight: 320, caption: "A photo by 贝莉儿 NG. (unsplash.com)" }, { src: "https://c7.staticflickr.com/9/8824/28868764222_19f3b30773_b.jpg", thumbnail: "https://c7.staticflickr.com/9/8824/28868764222_19f3b30773_n.jpg", thumbnailWidth: 226, thumbnailHeight: 320, caption: "A photo by Matthew Wiebe. (unsplash.com)" } ]).splice(0,16) }; ReactDOM.render(<Demo0 />, document.getElementById('demo0'));