I wanted to implement a simple image gallery showing some of the more interesting pictures I’ve taken on my journey of discovering photography. In addition I also wanted to have a section on the main page with my recent videos and I wanted them to be playable on the site instead of redirecting to my YT channel.
I started researching possible implementations for NextJS and came across the official Image Gallery Starter project. It uses Headless UI library for modal window implementation. This was great because I could also familiarize myself with yet another UI components library for React/JS, but... First things first, what is “headless component library” library? Let me ask ChatGPT about it? :)
A headless component library is a collection of reusable UI components that can be used in a variety of contexts, such as in a web or mobile app, without the need for a specific user interface or layout. These components are typically built using a JavaScript framework or library and can be easily integrated into different projects. They are designed to be independent of any particular user interface or layout, so they can be used in a variety of contexts.
Thank you, ChatGPT, this is a pretty good general definition for such libraries. There are a number of alternatives such as Radix UI, Reach UI, Chakra UI, etc. Brief overview and comparison between them lead me to a conclusion that despite the fact that Headless UI has a smaller number of components compared to others it was a good candidate for starters like me as its well documented and simple to use.
Image gallery starter project from NextJS also uses Framer Motion library for animating simple carousel component and Tailwind CSS for styling. These were all good learning points for me. It took me about a day in total to read through the stater project's code and implement the solution in my project with just UI issues outstanding.
When photo gallery, backed by the content from Claudinary, was functional my next step was to implement similar modal window but for my Youtube videos. Image gallery statically generates pages (i.e. getStaticPaths() and getStaticProps()) for each gallery picture and my initial thought process video modal was evolving around similar approach, but, after giving a little bit of a thought and for the sake of learning and experimenting, I decided to implement a slightly simplier solution. I created a simple React component instead of a dynamic page.
import { useState, useRef} from 'react'
import { Dialog} from '@headlessui/react'
import ReactPlayer from 'react-player/youtube'
import { useRouter } from 'next/router'
import useKeypress from 'react-use-keypress'
function VideoModal() {
const [isOpen, setIsOpen] = useState(true);
const focusRef = useRef();
const router = useRouter();
const { videoId } = router.query
function handleClose() {
setIsOpen(false);
router.push('/', undefined, { shallow: true });
}
useKeypress('Escape', () => {
handleClose();
})
return (
<Dialog
open={isOpen}
onClose={handleClose}
initialFocus={focusRef}
className="relative z-10"
>
<div className="fixed inset-0 overflow-y-auto bg-yellow">
<div className="flex min-h-full items-center justify-center p-4">
<Dialog.Panel className="responsive__modal">
<ReactPlayer className="relative z-20 flex"
url={videoId}
controls
/>
</Dialog.Panel>
</div>
</div>
</Dialog>
)
}
export default VideoModal;
Headless UI components take care of accessibility features for us, but they have no internal state management built into them and we need to control their state externally. Image gallery implementation uses small “react-hooks-global-state“ library with a custom hook for tracking currently opened picture, but for video playback it won’t be necessary. Dialog component has “open={isOpen}” attribute which is responsible for rendering itself on a page. Clicking outside of the panel’s boundaries or pressing Esc key closes the modal window automatically. For my purposes this is all I needed. Handler method for closing event will redirect back to the main page using NextJs router.
I've spent around 2 days in total for implementing image gallery and video display in a modal window addressing most of the styling issues as the last step before the launch.