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!