Skip to main content

Overview

The Dev Showcase modal system provides lightbox functionality for certificates and project images. It features smooth animations, keyboard navigation, and prevents body scrolling when modals are active.

Certificate Modal

Displays certificates with title and date metadata

Image Modal

Full-screen image viewer for project screenshots

Architecture

Core Functions

The modal system uses two simple functions for all interactions:
modal-manager.js (lines 12-22)
function openModal(modal) {
    if (!modal) return;
    modal.classList.add('active');
    document.body.style.overflow = 'hidden';
}

function closeModal(modal) {
    if (!modal) return;
    modal.classList.remove('active');
    document.body.style.overflow = '';
}
The modal system prevents body scrolling by setting overflow: hidden on the body element when a modal is active.

Certificate Modal

HTML Structure

The certificate modal displays both the certificate image and metadata:
<div id="certificateModal" class="certificate-modal">
    <div class="modal-content">
        <div class="modal-close-btn" id="certificateModalCloseBtn">
            <svg><!-- Close icon --></svg>
        </div>
        <img id="certificateModalImage" src="" alt="">
        <div class="certificate-modal-info">
            <h3 id="certificateModalTitle"></h3>
            <p id="certificateModalDate"></p>
        </div>
    </div>
</div>

Event Handler

Certificate cards open the modal with their data:
modal-manager.js (lines 24-37)
document.querySelectorAll('.certificate-card').forEach(card => {
    card.addEventListener('click', () => {
        const img = card.querySelector('img');
        const name = card.querySelector('.certificate-info p:first-child');
        const date = card.querySelector('.certificate-info span');
        if (!img || !certModal) return;

        certModalImg.src = img.src;
        certModalImg.alt = img.alt;
        if (certModalTitle) certModalTitle.textContent = name ? name.textContent : '';
        if (certModalDate) certModalDate.textContent = date ? date.textContent : '';
        openModal(certModal);
    });
});

Certificate Card HTML

<div class="certificate-card">
    <div class="certificate-image-container">
        <img src="cert.jpg" alt="Certificate name">
    </div>
    <div class="certificate-info">
        <p>Certificate Title</p>
        <span>June 2024</span>
    </div>
</div>

Image Modal

Simple Image Viewer

The image modal provides a clean, full-screen viewing experience:
modal-manager.js (lines 42-49)
document.querySelectorAll('.left-pnl.img-pnl img').forEach(img => {
    img.addEventListener('click', () => {
        if (!imageModal || !imageModalImg) return;
        imageModalImg.src = img.src;
        imageModalImg.alt = img.alt;
        openModal(imageModal);
    });
});

HTML Structure

<div id="imageModal" class="image-modal">
    <div class="modal-content">
        <div class="modal-close-btn" id="modalCloseBtn">
            <svg><!-- Close icon --></svg>
        </div>
        <img id="modalImage" src="" alt="">
    </div>
</div>

Closing Modals

Multiple Close Methods

Modals can be closed in three ways:
modal-manager.js (lines 39-40)
if (certModalClose) 
    certModalClose.addEventListener('click', () => closeModal(certModal));
The Escape key handler closes all active modals, providing a universal exit method.

CSS Styling

modal.css (lines 1-22)
.image-modal,
.certificate-modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.9);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--transition-speed) var(--transition-easing);
}

.image-modal.active,
.certificate-modal.active {
    opacity: 1;
    pointer-events: auto;
}

Zoom Animation

Modals animate in with a zoom effect:
modal.css (lines 24-41)
.modal-content {
    position: relative;
    max-width: 90%;
    max-height: 90%;
    animation: modalZoom 0.3s var(--transition-easing);
}

@keyframes modalZoom {
    from {
        transform: scale(0.8);
        opacity: 0;
    }

    to {
        transform: scale(1);
        opacity: 1;
    }
}

Close Button Styles

modal.css (lines 49-76)
.modal-close-btn {
    position: absolute;
    top: -50px;
    right: 0;
    width: 40px;
    height: 40px;
    background-color: var(--color-accent-red);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all var(--transition-speed) var(--transition-easing);
}

.modal-close-btn:hover {
    background-color: var(--color-accent-red-light);
    transform: rotate(90deg);
}

.modal-close-btn svg {
    width: 24px;
    height: 24px;
    stroke: #ffffff;
    stroke-width: 2;
    stroke-linecap: round;
}
The close button rotates 90 degrees on hover for a playful interaction.

Certificate Grid

Responsive Grid Layout

modal.css (lines 93-99)
.certificates-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 1.5rem;
    margin-top: 2rem;
    margin-bottom: 2rem;
}

Certificate Card Styles

modal.css (lines 101-132)
.certificate-card {
    background-color: var(--color-bg-tertiary);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    overflow: hidden;
    cursor: pointer;
    transition: all var(--transition-speed) var(--transition-easing);
}

.certificate-card:hover {
    border-color: var(--color-border-hover);
    transform: translateY(-5px);
}

.certificate-image-container {
    width: 100%;
    height: 180px;
    overflow: hidden;
    background-color: var(--color-bg-secondary);
}

.certificate-image-container img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--transition-speed) var(--transition-easing);
}

.certificate-image-container:hover img {
    transform: scale(1.04);
}

Project Image Integration

Project images automatically open in the modal:
<div class="project-info">
    <div class="left-pnl img-pnl">
        <img src="project-screenshot.jpg" alt="Project Screenshot">
    </div>
    <div class="right-pnl info-pnl">
        <h4>Project Details</h4>
        <p>Description...</p>
    </div>
</div>

Image Panel Styles

carousel.css (lines 212-221)
.img-pnl img {
    width: 100%;
    border-radius: 8px;
    cursor: pointer;
    transition: all var(--transition-speed) var(--transition-easing);
}

.img-pnl img:hover {
    transform: scale(1.05);
}

Initialization

The modal system initializes on page load:
modal-manager.js (lines 1-60)
document.addEventListener('DOMContentLoaded', () => {
    const certModal = document.getElementById('certificateModal');
    const certModalImg = document.getElementById('certificateModalImage');
    const certModalTitle = document.getElementById('certificateModalTitle');
    const certModalDate = document.getElementById('certificateModalDate');
    const certModalClose = document.getElementById('certificateModalCloseBtn');

    const imageModal = document.getElementById('imageModal');
    const imageModalImg = document.getElementById('modalImage');
    const imageModalClose = document.getElementById('modalCloseBtn');

    // Event listeners setup...
});

Usage Examples

Creating a Certificate Card

<div class="certificates-grid">
    <div class="certificate-card">
        <div class="certificate-image-container">
            <img src="cert-thumbnail.jpg" alt="Certificate">
        </div>
        <div class="certificate-info">
            <p>Microsoft Azure Fundamentals</p>
            <span>March 2024</span>
        </div>
    </div>
</div>

Creating a Project Image

<div class="left-pnl img-pnl">
    <img src="project.jpg" alt="Project Screenshot">
</div>
Ensure images have appropriate alt attributes for accessibility.

Features Summary

Prevents background scrolling when modal is open by setting document.body.style.overflow = 'hidden'.
Press Escape to close any active modal.
Clicking the modal background (not the content) closes the modal.
Modals zoom in from 0.8 scale to 1.0 over 0.3 seconds.
Modal background fades in/out using CSS transitions.

Browser Compatibility

  • Modern browsers: Full support
  • CSS Grid: Required for certificate grid layout
  • CSS Animations: All modern browsers
  • classList API: All modern browsers

Accessibility Considerations

1

Focus Management

Consider adding focus trap within modal for keyboard navigation
2

ARIA Labels

Add role="dialog" and aria-modal="true" to modal containers
3

Screen Reader Support

Include aria-label on close buttons
4

Alt Text

Always provide descriptive alt text for images

Build docs developers (and LLMs) love