Introduction: When Code Meets Chemistry

Every developer has that moment when a project becomes more than just lines of code—it becomes a portal to learning. For me, that project was the Periodic Table Explorer, a web application that transforms the classic periodic table into an interactive, information-rich experience.

Check out the live project here - https://playground.learncomputer.in/periodic-table-explorer/

Why Another Periodic Table? 🤔

Let's be honest: most periodic tables are boring. They're static, lifeless grids that do little more than sit there. I wanted to create something different—a tool that would:

  • Spark curiosity about chemical elements
  • Make scientific information accessible
  • Provide an intuitive, engaging user experience

Project Overview: What We'll Build 🚀

An interactive web application that allows users to:

  • Browse elements in a visually appealing grid
  • Switch between grid and list views
  • Search elements quickly
  • Click on any element to reveal detailed information

Tech Stack 💻

  • Frontend: HTML5, CSS3
  • Interactivity: Vanilla JavaScript
  • Data Source: Public JSON API
  • Design: Responsive, modern UI

Setting Up the HTML Structure

</span>
 lang="en">

     charset="UTF-8">
     name="viewport" content="width=device-width, initial-scale=1.0">
    Periodic Table Explorer
     rel="stylesheet" href="styles.css">
     href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&family=Roboto:wght@300;400;700&family=Lato:wght@300;400;700&display=swap" rel="stylesheet">


     class="container">
        
            Periodic Table Explorer
             class="controls">
                 type="text" id="search" placeholder="Search elements...">
                 id="view-toggle">List View
            
        

         class="periodic-table" id="periodic-table">

         class="modal" id="element-modal">
             class="modal-content">
                 class="close">×
                 class="modal-body" id="modal-body">
                     class="info-section" id="info-section">
                     id="three-container" style="width: 100%; height: 400px;">
                
            
        
    
    <span class="na">src="script.js">





    Enter fullscreen mode
    


    Exit fullscreen mode
    





  
  
  Key HTML Components:

Main container
Search input
View toggle button
Modal for element details

  
  
  Styling with CSS: Making It Look Awesome 🎨

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    background: linear-gradient(135deg, #1e1e1e, #2c3e50);
    color: #fff;
    min-height: 100vh;
    font-family: 'Roboto', sans-serif;
}

.container {
    max-width: 1400px;
    margin: 0 auto;
    padding: 40px;
}

header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 40px;
    background: rgba(255, 255, 255, 0.05);
    padding: 20px;
    border-radius: 20px;
    backdrop-filter: blur(10px);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}

h1 {
    font-size: 2.8rem;
    font-weight: 700;
    color: #00ffcc;
    font-family: 'Lato', sans-serif;
}

.controls {
    display: flex;
    gap: 15px;
}

input, button {
    padding: 12px 25px;
    border: none;
    border-radius: 50px;
    font-size: 1rem;
    transition: all 0.4s ease;
    background: rgba(255, 255, 255, 0.1);
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
    font-family: 'Poppins', sans-serif;
}

input {
    backdrop-filter: blur(5px);
    color: #fff;
}

input::placeholder {
    color: rgba(255, 255, 255, 0.7);
    opacity: 1;
}

input:focus {
    outline: none;
    box-shadow: 0 0 15px rgba(0, 255, 204, 0.5);
}

button {
    background: #00ffcc;
    color: #1e1e1e;
    cursor: pointer;
}

button:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 20px rgba(0, 255, 204, 0.4);
}

.periodic-table {
    display: grid;
    grid-template-columns: repeat(18, 1fr);
    grid-template-rows: repeat(10, 1fr);
    gap: 6px;
    padding: 20px;
    background: rgba(255, 255, 255, 0.03);
    border-radius: 25px;
    backdrop-filter: blur(15px);
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
    min-height: 500px;
    overflow: auto;
}

.periodic-table.list-view {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.element {
    width: 60px;
    height: 60px;
    display: grid;
    grid-template-areas: 
        "number ."
        "symbol symbol"
        "name name";
    grid-template-columns: auto 1fr;
    grid-template-rows: auto 1fr auto;
    justify-items: center;
    align-items: center;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.3s ease;
    backdrop-filter: blur(5px);
    border: 1px solid rgba(255, 255, 255, 0.1);
    padding: 4px;
}

.periodic-table.list-view .element {
    width: 100%;
    height: auto;
    padding: 10px;
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
}

.element:hover {
    transform: scale(1.1) rotate(2deg);
    box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
    filter: brightness(1.2);
}

.periodic-table.list-view .element:hover {
    transform: scale(1.05);
    rotate: 0deg;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}

.element .number {
    grid-area: number;
    font-size: 0.7rem;
}

.element .symbol {
    grid-area: symbol;
    font-size: 1.1rem;
    font-weight: 600;
}

.element .name {
    grid-area: name;
    font-size: 0.6rem;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.element:hover .name {
    opacity: 1;
}

/* Modal Styles */
.modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.8);
    backdrop-filter: blur(3px);
    z-index: 1000;
}

.modal-content {
    background: rgba(30, 30, 30, 0.95);
    margin: 5% auto;
    padding: 30px;
    width: 90%;
    max-width: 800px;
    border-radius: 20px;
    position: relative;
    animation: slideIn 0.4s ease;
    box-shadow: 0 15px 50px rgba(0, 0, 0, 0.5);
    color: #fff;
    max-height: 80vh;
    overflow-y: auto;
}

@keyframes slideIn {
    from { transform: translateY(-100px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

.close {
    position: absolute;
    right: 20px;
    top: 15px;
    font-size: 30px;
    cursor: pointer;
    color: #fff;
    transition: all 0.3s ease;
}

.close:hover {
    color: #ff6666;
    transform: rotate(90deg);
}

.modal-body h2 {
    color: #00ffcc;
    margin-bottom: 20px;
    font-size: 2rem;
    font-family: 'Lato', sans-serif;
}

.modal-body .info-grid {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 15px;
    font-family: 'Poppins', sans-serif;
}

.modal-body .info-grid p {
    margin: 5px 0;
}

.modal-body .info-grid p strong {
    color: #00ffcc;
    font-weight: 700;
}

.modal-body .info-grid p a {
    color: #66ccff;
    text-decoration: underline;
}

.modal-body .info-grid p a:hover {
    color: #99eeff;
}

.modal-body .info-grid p img {
    max-width: 100%;
    height: auto;
    margin-top: 10px;
    border-radius: 10px;
}

#three-container {
    width: 100%;
    height: 400px;
    margin-top: 20px;
    border-radius: 10px;
    overflow: hidden;
    background: #222;
}

/* High-contrast colors */
.alkali-metal { background: #ff6b6b; color: #000; }
.alkaline-earth-metal { background: #ffa94d; color: #000; }
.transition-metal { background: #ffd700; color: #000; }
.post-transition-metal { background: #95e063; color: #000; }
.metalloid { background: #63e6be; color: #000; }
.nonmetal { background: #63cdda; color: #000; }
.noble-gas { background: #74c0fc; color: #000; }
.lanthanide { background: #cc99ff; color: #000; }
.actinide { background: #ff99cc; color: #000; }

/* Ensure text inherits color from parent */
.element .number,
.element .symbol,
.element .name {
    color: inherit;
}

/* Responsive Design */
@media (max-width: 768px) {
    .periodic-table {
        grid-template-columns: repeat(9, 1fr);
    }
    header {
        flex-direction: column;
        gap: 20px;
    }
    .modal-body .info-grid {
        grid-template-columns: 1fr;
    }
    .element {
        width: 50px;
        height: 50px;
    }
}



    Enter fullscreen mode
    


    Exit fullscreen mode
    





  
  
  Design Highlights:

Gradient background
Flexible grid layout
Responsive design
Smooth transitions and hover effects

  
  
  JavaScript: The Interactive Magic ✨

document.addEventListener('DOMContentLoaded', () => {
    const table = document.getElementById('periodic-table');
    const modal = document.getElementById('element-modal');
    const modalBody = document.getElementById('modal-body');
    const closeBtn = document.querySelector('.close');
    const viewToggle = document.getElementById('view-toggle');
    const searchInput = document.getElementById('search');

    fetch('PeriodicTableJSON.json')
        .then(response => response.json())
        .then(data => {
            const elements = data.elements;
            createPeriodicTable(elements);
            setupEventListeners(elements);
        })
        .catch(error => console.error('Error fetching data:', error));

    function createPeriodicTable(elements) {
        table.innerHTML = '';
        elements.forEach(element => {
            const div = document.createElement('div');
            div.className = `element ${getCategoryClass(element.category)}`;
            div.innerHTML = `
                ${element.number}
                ${element.symbol}
                ${element.name}
            `;
            div.dataset.atomicNumber = element.number;

            const period = element.ypos;
            const group = element.xpos;
            let row = period;
            let col = group;

            if (element.number >= 58 && element.number <= 71) {
                row = 8;
                col = element.number - 55;
            } else if (element.number >= 90 && element.number <= 103) {
                row = 9;
                col = element.number - 87;
            }

            div.style.gridRow = row;
            div.style.gridColumn = col;
            table.appendChild(div);
        });
    }

    function setupEventListeners(elements) {
        const elementNodes = document.querySelectorAll('.element');
        elementNodes.forEach(element => {
            element.addEventListener('click', (e) => {
                e.stopPropagation();
                const atomicNumber = parseInt(element.dataset.atomicNumber, 10);
                const elementData = elements.find(el => el.number === atomicNumber);
                if (elementData) {
                    showModal(elementData);
                }
            });
        });

        closeBtn.addEventListener('click', (e) => {
            e.stopPropagation();
            modal.style.display = 'none';
        });

        document.addEventListener('click', (e) => {
            if (e.target === modal) {
                modal.style.display = 'none';
            }
        });

        viewToggle.addEventListener('click', () => {
            table.classList.toggle('list-view');
            viewToggle.textContent = table.classList.contains('list-view') ? 'Grid View' : 'List View';
            if (table.classList.contains('list-view')) {
                document.querySelectorAll('.element').forEach(el => {
                    el.style.gridRow = 'auto';
                    el.style.gridColumn = 'auto';
                });
            } else {
                createPeriodicTable(elements);
            }
        });

        searchInput.addEventListener('input', (e) => {
            const searchTerm = e.target.value.toLowerCase();
            document.querySelectorAll('.element').forEach(el => {
                const name = el.querySelector('.name').textContent.toLowerCase();
                const symbol = el.querySelector('.symbol').textContent.toLowerCase();
                el.style.display = (name.includes(searchTerm) || symbol.includes(searchTerm)) ? '' : 'none';
            });
        });
    }

    function showModal(element) {
        modalBody.innerHTML = `
            ${element.name} (${element.symbol})
            
                Atomic Number: ${element.number}
                Atomic Mass: ${element.atomic_mass}
                Symbol: ${element.symbol}
                Category: ${element.category}
                Period: ${element.ypos}
                Group: ${element.xpos}
                Density: ${element.density || 'N/A'} g/cm³
                Melting Point: ${element.melt || 'N/A'} K
                Boiling Point: ${element.boil || 'N/A'} K
                Appearance: ${element.appearance || 'N/A'}
                Phase: ${element.phase || 'N/A'}
                Molar Heat: ${element.molar_heat || 'N/A'} J/(mol·K)
                Discovered By: ${element.discovered_by || 'N/A'}
                Named By: ${element.named_by || 'N/A'}
                Summary: ${element.summary || 'N/A'}
                Electron Configuration: ${element.electron_configuration || 'N/A'}
                Semantic Electron Config: ${element.electron_configuration_semantic || 'N/A'}
                Shells: ${element.shells ? element.shells.join(', ') : 'N/A'}
                Ionization Energies: ${element.ionization_energies ? element.ionization_energies.join(', ') : 'N/A'} kJ/mol
                ${element.spectral_img ? `Spectral Image: ${element.spectral_img}" target="_blank">View Spectral Image` : 'Spectral Image: N/A'}
                ${element.bohr_model_image ? `Bohr Model Image: ${element.bohr_model_image}" alt="Bohr Model of ${element.name}" style="max-width: 200px;">` : 'Bohr Model Image: N/A'}
                ${element.source ? `Source: ${element.source}" target="_blank">Source` : 'Source: N/A'}
                ${element.image ? `
                    Image Title: ${element.image.title || 'N/A'}
                    Image: ${element.image.url}" alt="${element.image.title || 'Element Image'}" style="max-width: 200px;">
                ` : 'Image: N/A'}
            
        `;
        modal.style.display = 'block';
    }

    function getCategoryClass(category) {
        const classes = {
            'alkali metal': 'alkali-metal',
            'alkaline earth metal': 'alkaline-earth-metal',
            'transition metal': 'transition-metal',
            'post-transition metal': 'post-transition-metal',
            'metalloid': 'metalloid',
            'nonmetal': 'nonmetal',
            'noble gas': 'noble-gas',
            'lanthanide': 'lanthanide',
            'actinide': 'actinide'
        };
        return classes[category.toLowerCase()] || '';
    }
});



    Enter fullscreen mode
    


    Exit fullscreen mode
    





  
  
  Core Functions:

Fetching element data
Creating periodic table grid
Handling element clicks
Implementing search functionality

  
  
  Data Fetching: Bringing Elements to Life 📊

 fetch('PeriodicTableJSON.json')
        .then(response => response.json())
        .then(data => {
            const elements = data.elements;
            createPeriodicTable(elements);
            setupEventListeners(elements);
        })
        .catch(error => console.error('Error fetching data:', error));



    Enter fullscreen mode
    


    Exit fullscreen mode
    





  
  
  Creating the Periodic Table Grid 🏗️

function createPeriodicTable(elements) {
    // Dynamically generate element tiles
    // Position elements in correct grid locations
}



    Enter fullscreen mode
    


    Exit fullscreen mode
    





  
  
  The Element Modal: A Deep Dive 🔍
When users click an element, they'll see:
Atomic details
Physical properties
Historical information
Spectral images (where available)


function showElementDetails(element) {
    // Populate modal with comprehensive element information
}



    Enter fullscreen mode
    


    Exit fullscreen mode
    





  
  
  Innovative Features 🌟


Dynamic View Modes


Grid view (classic periodic table)
List view (detailed, scrollable)



Real-time Search


Instantly filter elements
Search by name or symbol



Responsive Design


Works perfectly on desktop and mobile



  
  
  Challenges and Learnings 🧠
Building this app wasn't just about coding—it was about:
Managing complex data structures
Creating intuitive user interfaces
Optimizing performance
Making science accessible

  
  
  Performance Considerations 🚄

Efficient data loading
Minimal DOM manipulations
Lightweight, fast-loading design

  
  
  Future Roadmap 🗺️
Potential enhancements:
3D element visualizations
Interactive learning quizzes
More detailed scientific comparisons

  
  
  Live Demo 🔗


Live App: Periodic Table Explorer


  
  
  Closing Thoughts: More Than Just a Table 🌈
The Periodic Table Explorer is a testament to how web development can transform educational content. It's not just about displaying information—it's about creating an experience that inspires curiosity and makes learning fun.
  
  
  Learning Opportunities 📚
This project is perfect for developers who want to:
Practice vanilla JavaScript
Work with JSON data
Create interactive web applications
Understand responsive design principles
Happy Coding and Exploring! 🚀👩‍💻👨‍💻Crafted with curiosity, code, and a dash of chemical enthusiasm
  
  
  🔍 Quick Tips for Aspiring Developers

Always think about user experience
Make your projects interactive
Never stop learning!