The Lightbox kit is a popup window overlay that will appear on top of your webpage and cover the entirety of the screen. It can be used to display a group of images that the user can swipe through, zoom into and view. The button in the top left of the header can be used to close the overlay and exit back to your webpage. Click the images in the examples below to see Lightbox in action.
Lightbox contains several props: photos
(an array of urls), initialPhoto
(a number), onClickLeft
(an optional callback function for top left close button), title
and description
(string or custom components), icon
( optional prop for the close button in the top left of the header), navRight
(optional prop that renders clickable text in the top right section of the header), onClickRight
(optional callback function of navRight) and onChange
(optional event handler prop exposing index of current photo).
import React, { useState } from 'react' import { Flex, Image } from 'playbook-ui' import Lightbox from 'playbook-ui' const LightboxDefault = (props) => { const photos = [ 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', ] const [selectedPhoto, setSelectedPhoto] = useState(0) const [showLightbox, toggleShowLightbox] = useState(false) const handleCloseLightbox = () => { toggleShowLightbox(!showLightbox) setSelectedPhoto(null) } const onPhotoClick = (photoIndex) => { toggleShowLightbox(!showLightbox) setSelectedPhoto(photoIndex) } return ( <> <div> {showLightbox ? ( <Lightbox icon="times" initialPhoto={selectedPhoto} onClose={handleCloseLightbox} photos={photos} /> ) : ( <div className="PhotoViewer"> <Flex> {photos.map((photo, index) => { return ( <div key={photo[index]} onClick={() => onPhotoClick(index)} > <Image cursor="pointer" marginRight="xl" rounded size="lg" url={photo} /> <div className="overlay" /> </div> ) })} </Flex> </div> )} </div> </> ) } export default LightboxDefault
When multiple images are passed to the Lightbox kit, it will also display scrollable thumbnails at the bottom of the screen for easier access to all images. In addition to the scrollable thumbnails, larger screens provide arrow buttons on the left and right of the image itself for easier scrolling while on mobile devices the kit allows for swiping.
This example also highlights the use of the optional onChange
prop which is an event handler prop that tracks the index of the image being viewed and exposes it for use by the developer.
import React, { useState } from 'react' import { Flex, Image } from 'playbook-ui' import Lightbox from 'playbook-ui' const LightboxMultiple = (props) => { const photos = [ 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', ] const [selectedPhoto, setSelectedPhoto] = useState(0) const [light, toggleLight] = useState(false) const handleCloseLightbox = () => { toggleLight(!light) setSelectedPhoto(null) } const onPhotoClick = (photo) => { toggleLight(!light) setSelectedPhoto(photo) } const exampleStyles = { width: "100%", overflow: "auto" } return ( <div> {light ? ( <Lightbox icon="times" initialPhoto={selectedPhoto} onChange={(index) => console.log(`current photo index: ${index}`)} onClose={handleCloseLightbox} photos={photos} /> ) : ( <div className="PhotoViewer" style={exampleStyles} > <Flex> {photos.map((photo, index) => { return ( <div key={index} onClick={() => onPhotoClick(index)} > <Image cursor="pointer" marginRight="xl" rounded size="lg" url={photo} /> <div className="overlay" /> </div> ) })} </Flex> </div> )} </div> ) } export default LightboxMultiple
title
and description
are optional props that can be passed to the kit if needed. Each of these props can take a string OR a custom component. This example highlights what the kit will look like when only strings are passed as title
and description
.
import React, { useState } from 'react' import { Flex, Image } from 'playbook-ui' import Lightbox from 'playbook-ui' const LightboxCompoundComponent = (props) => { const photos = [ 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1501045337096-542a73dafa4f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2052&q=80', 'https://images.unsplash.com/photo-1563693998336-93c10e5d8f91?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80,', ] const [selectedPhoto, setSelectedPhoto] = useState(0) const [showLightbox, toggleShowLightbox] = useState(false) const handleCloseLightbox = () => { toggleShowLightbox(!showLightbox) setSelectedPhoto(null) } const onPhotoClick = (photo) => { toggleShowLightbox(!showLightbox) setSelectedPhoto(photo) } const exampleStyles = { width: "100%", overflow: "auto" } return ( <> <div> {showLightbox ? ( <Lightbox description='Description Content Goes Here.' initialPhoto={selectedPhoto} onClose={handleCloseLightbox} photos={photos} title='Windows, Sidings, & Gutters' /> ) : ( <div className="PhotoViewer" style={exampleStyles} > <Flex> {photos.map((photo, index) => { return ( <div key={index} onClick={() => onPhotoClick(index)} > <Image cursor="pointer" marginRight="xl" rounded size="lg" url={photo} /> <div className="overlay" /> </div> ) })} </Flex> </div> )} </div> </> ) } export default LightboxCompoundComponent
title
and description
props also accept custom components if needed. The optional navRight
prop only accepts a string that translates into a clickable button. onClickRight
prop can be used to pass in click function for navRight
.
import React, { useState } from "react"; import { Flex, Image, Title, Pill } from "playbook-ui"; import Lightbox from 'playbook-ui' const LightboxCustomHeader = (props) => { const photos = [ "https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80", "https://images.unsplash.com/photo-1501045337096-542a73dafa4f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2052&q=80", "https://images.unsplash.com/photo-1563693998336-93c10e5d8f91?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1470&q=80,", ]; const [selectedPhoto, setSelectedPhoto] = useState(0); const [showLightbox, toggleShowLightbox] = useState(false); const handleCloseLightbox = () => { toggleShowLightbox(!showLightbox); setSelectedPhoto(null); }; const onPhotoClick = (photo) => { toggleShowLightbox(!showLightbox); setSelectedPhoto(photo); }; const exampleStyles = { width: "100%", overflow: "auto", }; const customTitle = ( <Title dark paddingBottom="xxs" size={4} > My Custom Title </Title> ); const customDescription = ( <> <Title dark size={4} text="Tags" /> <Pill text="3" variant="success" /> </> ); return ( <> <div> {showLightbox ? ( <Lightbox description={customDescription} initialPhoto={selectedPhoto} navRight="All Photos" onClickRight={()=> alert("Clicked!")} onClose={handleCloseLightbox} photos={photos} title={customTitle} /> ) : ( <div className="PhotoViewer" style={exampleStyles} > <Flex> {photos.map((photo, index) => { return ( <div key={index} onClick={() => onPhotoClick(index)} > <Image marginRight="xl" rounded size="lg" url={photo} /> <div className="overlay" /> </div> ); })} </Flex> </div> ) } </div> </> ); }; export default LightboxCustomHeader;
The currentPhotoIndex
prop allows the user to pass a number to the lightbox that will set the current slide by index. This can be leveraged if the user wants to change slides using custom buttons. To do this, the user must also make use of the current slide's index that is exposed by the onChange
prop.
import React, { useState } from 'react' import { Flex, Image, Button, Body, FlexItem } from 'playbook-ui' import Lightbox from 'playbook-ui' const LightboxCurrentPhoto = (props) => { const photos = [ 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', 'https://images.unsplash.com/photo-1638727228877-d2a79ab75e68?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2668&q=80', 'https://images.unsplash.com/photo-1526657782461-9fe13402a841?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1984&q=80', 'https://images.unsplash.com/photo-1523057530100-383d7fbc77a1?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2669&q=80', ] const [light, toggleLight] = useState(false) //Setting state with the index of the current slide exposed by the onChange prop const [active, setActive] = useState(0) //Setting state for the current photo to pass to the kit const [currentPhoto, setCurrentPhoto] = useState(active) const handleCloseLightbox = () => { toggleLight(!light) } const onPhotoClick = () => { toggleLight(!light) } const exampleStyles = { width: "100%", overflow: "auto" } return ( <div className="lightbox_doc_example_custom"> {light ? ( <> <Flex alignItems="center" className='custom_lightbox_sidebar' justifyContent="center" > <Flex margin='lg' orientation='column' > <Body marginBottom='md'> This UI is for demonstration purposes only to demonstrate how external buttons can be used to change the slides. </Body> <FlexItem alignSelf="center"> <Flex justifyContent="center"> <Button onClick={()=> setCurrentPhoto(active > 0 ? active - 1 : 0)} > Back </Button> <Button marginLeft='sm' onClick={() => setCurrentPhoto(active < photos.length - 1 ? active + 1 : photos.length - 1)} > Next </Button> </Flex> </FlexItem> </Flex> </Flex> <Lightbox currentPhotoIndex={currentPhoto} icon="times" onChange={(index) => setActive(index)} onClose={handleCloseLightbox} photos={photos} /> </> ) : ( <div className="PhotoViewer" style={exampleStyles} > <Flex> {photos.map((photo, index) => { return ( <div key={index} onClick={() => onPhotoClick(index)} > <Image cursor="pointer" marginRight="xl" rounded size="lg" url={photo} /> <div className="overlay" /> </div> ) })} </Flex> </div> )} </div> ) } export default LightboxCurrentPhoto