skip to Main Content

I have a list of images to display thumbnails. On top of that, for each image, I want to click it to show the image on the full size.

To achieve this, I use Modal and useDisclosure() from @nextui-org/react. Below is my code:

    const { isOpen, onOpen, onOpenChange } = useDisclosure();
                        <Card className="" isPressable onPress={onOpen}>
                            <CardHeader className="flex-col items-start">
                                <p className="text-tiny uppercase font-bold">id:12345678</p>
                                <small className="text-default-500">date:2024-01</small>
                                <h4 className="font-bold text-large">name</h4>
                            </CardHeader>
                            <CardBody className="overflow-visible">
                                {/* <a href="https://www.baidu.com" target="_blank"> */}
                                <Image
                                    alt="Card background"
                                    className="object-cover rounded-xl"
                                    src="/patent/1.png"
                                    height={270}
                                    width={270}
                                />
                                {/* </a> */}
                            </CardBody>
                        </Card>
                        <Modal isOpen={isOpen} onOpenChange={onOpenChange} size="5xl" scrollBehavior="outside" id="modal">
                            <ModalContent>
                                {() => (
                                    <>
                                        <ModalBody>
                                            <Image
                                                alt="Card background"
                                                className="object-cover rounded-xl"
                                                src="/patent/1.png"
                                                height={2000}
                                                width={2000}
                                            />
                                        </ModalBody>
                                    </>
                                )}
                            </ModalContent>
                        </Modal>

My question is, since I have a list of images, whose length is variable. It is not wise or elegant to hard-code a list of corresponding useDisclosure()

How can I auto create useDisclosure for each image?

2

Answers


  1. Problem :

    Show full size image in a Modal, by opening a Modal through pressable card

    Solution :

    You don’t need multiple Modal or useDisclosure() hooks, because you can just pass the selected image details to a Modal using a state.

    Code :

    I have kept code as minimum as possible (you may make necessary changes as needed)

    // 'use client' // IF USING NEXTJS UNCOMMENT THIS
    
    import { Card, CardBody, CardHeader, Modal, ModalBody, ModalContent, ModalHeader, useDisclosure } from '@nextui-org/react';
    import { useState } from 'react';
    
    const ImgCard = () => {
    
        const Images = [{
            "id": 1,
            "name": "Gertrude",
            "url": "http://dummyimage.com/1026x1003.png/ff4444/ffffff",
            "date": "08/15/2023"
        }, {
            "id": 2,
            "name": "Steve",
            "url": "http://dummyimage.com/1087x1100.png/5fa2dd/ffffff",
            "date": "08/17/2023"
        }, {
            "id": 3,
            "name": "Beauregard",
            "url": "http://dummyimage.com/1115x1032.png/dddddd/000000",
            "date": "12/21/2023"
        }, {
            "id": 4,
            "name": "Cinderella",
            "url": "http://dummyimage.com/1029x1141.png/cc0000/ffffff",
            "date": "08/14/2023"
        }, {
            "id": 5,
            "name": "Charmain",
            "url": "http://dummyimage.com/1140x1013.png/cc0000/ffffff",
            "date": "12/18/2023"
        }]
    
        const [ClickedImg, SetClickedImg] = useState(null)
        // STORES OBJECT {}, Image details 
        const { isOpen, onOpen, onOpenChange } = useDisclosure();
    
        return (
            <div className='flex gap-4 '>
                {
                    Images.map((v, i) => (
                        <Card className="" isPressable onPress={() => {
                            // SET IMAGE DETAILS
                            SetClickedImg(v)
                            // v = FULL OBJECT { "id": 1, "name": "Gertrude", "url": "http://dummyimage.com/1026x1003.png/ff4444/ffffff", "date": "08/15/2023" } 
                            onOpen()  // THEN OPEN MODAL
                        }}>
                            <CardHeader className="flex-col items-start">
                                <p className="text-tiny uppercase font-bold">{v.id}</p>
                                <small className="text-default-500">{v.date}</small>
                                <h4 className="font-bold text-large">{v.name}</h4>
                            </CardHeader>
                            <CardBody className="overflow-visible">
                                <img
                                    alt="Card background"
                                    className="object-cover rounded-xl w-60 h-60"
                                    src={v.url}
                                />
                            </CardBody>
                        </Card>
                    ))
                }
                <Modal
                    isOpen={isOpen} onOpenChange={onOpenChange} size="5xl"
                    scrollBehavior="outside" id="modal"
                >
                    <ModalContent>
                        {() => (
                            <>
                                {/*  ACCESS DETAILS FROM STATE */}
                                <ModalHeader className="flex flex-col gap-1">{ClickedImg.name}</ModalHeader>
                                <ModalBody>
    
                                    <img
                                        alt="Card background"
                                        className="object-cover rounded-xl"
                                        src={ClickedImg.url}
                                    // ACCESS DETAILS FROM STATE
                                    />
                                </ModalBody>
                            </>
                        )}
                    </ModalContent>
                </Modal>
            </div>
        );
    }
    export default ImgCard
    

    Explaination :

    • Images array contains object with image details,

    • const [ClickedImg, SetClickedImg] = useState(null) is used to store clicked image details

    • Then Card is mapped using Images array, & details are assigned in it. onPress function does two things sets state SetClickedImg(v) & then opens Modal by calling onOpen().

    • When Card is clicked, Modal opens & shows details using ClickedImg state.

    • Don’t forget to uncomment use client line if using NextJS.

    If this answer was solved your problem then mark it as solution. If this answer was very helpful then you may upvote. If you have any doubts, then please leave a comment (I will update answer as necessary)

    Login or Signup to reply.
  2. I did something similar, but I’ve refactor in your code. Hope this helps.

    import React, { useState } from 'react';
    import { Card, CardHeader, CardBody, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure } from '@nextui-org/react';
    enter code here
    import Image from 'next/image';
    
    const ImageGallery = ({ images }) => {
        const { isOpen, onOpen, onOpenChange } = useDisclosure();
        const [selectedImage, setSelectedImage] = useState(null);
    
    const handleOpen = (image) => {
        setSelectedImage(image);
        onOpen();
    };
    
    return (
        <>
            {images.map((image, index) => (
                <Card key={index} className="" isPressable onPress={() => handleOpen(image)}>
                    <CardHeader className="flex-col items-start">
                        <p className="text-tiny uppercase font-bold">id:{image.id}</p>
                        <small className="text-default-500">date:{image.date}</small>
                        <h4 className="font-bold text-large">{image.name}</h4>
                    </CardHeader>
                    <CardBody className="overflow-visible">
                        <Image
                            alt="Card background"
                            className="object-cover rounded-xl"
                            src={image.thumbnailSrc}
                            height={270}
                            width={270}
                        />
                    </CardBody>
                </Card>
            ))}
            {selectedImage && (
                <Modal isOpen={isOpen} onOpenChange={onOpenChange} size="5xl" scrollBehavior="outside" id="modal">
                    <ModalContent>
                        {() => (
                            <>
                             <ModalHeader>
                                    <h2>{selectedImage.name}</h2>
                                </ModalHeader>
                                <ModalBody>
                                    <Image
                                        alt="Card background"
                                        className="object-cover rounded-xl"
                                        src={selectedImage.fullSizeSrc}
                                        height={2000}
                                        width={2000}
                                    />
                                </ModalBody>
                                <ModalFooter>
                                    <Button onPress={onOpenChange}>Close</Button>
                                </ModalFooter>
                            </>
                        )}
                    </ModalContent>
                </Modal>
            )}
    
    
           </>
        );
      };
    

    This is an example of how to use.

    const images = [
        { 
          id: '', 
          date: '2021', 
          name: 'img1', 
          thumbnailSrc: '/stills/housePlan1.png', 
          fullSizeSrc: '/stills/housePlan2.
        } 
      ];
    

    How to use in your other functions

    export default function App() {
        return <ImageGallery images={images} />;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search