Skip to content

Instantly share code, notes, and snippets.

@KrishnanSriram
Created January 24, 2026 21:48
Show Gist options
  • Select an option

  • Save KrishnanSriram/71b59374c6847eaf7fe1e356d4eaa3eb to your computer and use it in GitHub Desktop.

Select an option

Save KrishnanSriram/71b59374c6847eaf7fe1e356d4eaa3eb to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Simple SPA</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.6;
color: #333;
}
header {
background: #4a90e2;
color: white;
padding: 1rem 2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
nav {
display: flex;
gap: 2rem;
margin-top: 1rem;
}
nav a {
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: 4px;
transition: background 0.3s;
}
nav a:hover {
background: rgba(255, 255, 255, 0.2);
}
nav a.active {
background: rgba(255, 255, 255, 0.3);
font-weight: bold;
}
main {
max-width: 1200px;
margin: 2rem auto;
padding: 0 2rem;
}
.view {
display: none;
animation: fadeIn 0.3s;
}
.view.active {
display: block;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
margin-bottom: 2rem;
}
h1,
h2 {
margin-bottom: 1rem;
color: #2c3e50;
}
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin-top: 2rem;
}
.feature-card {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 8px;
border-left: 4px solid #4a90e2;
}
.feature-card h3 {
color: #4a90e2;
margin-bottom: 0.5rem;
}
footer {
text-align: center;
padding: 2rem;
background: #f8f9fa;
margin-top: 4rem;
color: #666;
}
form {
display: flex;
flex-direction: column;
gap: 1rem;
max-width: 500px;
}
input,
textarea {
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 4px;
font-family: inherit;
}
button {
background: #4a90e2;
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1rem;
transition: background 0.3s;
}
button:hover {
background: #357abd;
}
</style>
</head>
<body>
<header>
<h1>My Simple SPA</h1>
<nav id="nav">
<a href="#home" class="nav-link active">Home</a>
<a href="#about" class="nav-link">About</a>
<a href="#contact" class="nav-link">Contact</a>
</nav>
</header>
<main>
<!-- Home View -->
<div id="home" class="view active">
<div class="card">
<h2>Welcome to My Single Page Application</h2>
<p>This is a simple SPA built with vanilla HTML, CSS, and JavaScript. No frameworks required!</p>
<div class="feature-grid">
<div class="feature-card">
<h3>⚡ Fast</h3>
<p>No page reloads, instant navigation between views</p>
</div>
<div class="feature-card">
<h3>📱 Responsive</h3>
<p>Works seamlessly on desktop, tablet, and mobile devices</p>
</div>
<div class="feature-card">
<h3>🎨 Modern</h3>
<p>Clean design with smooth animations and transitions</p>
</div>
<div class="feature-card">
<h3>🚀 Simple</h3>
<p>Easy to deploy as a static website anywhere</p>
</div>
</div>
</div>
</div>
<!-- About View -->
<div id="about" class="view">
<div class="card">
<h2>About This Project</h2>
<p>This SPA demonstrates the core concepts of single-page applications:</p>
<ul style="margin-left: 2rem; margin-top: 1rem; line-height: 2;">
<li>Client-side routing using URL hash</li>
<li>Dynamic content switching without page reloads</li>
<li>Smooth transitions between views</li>
<li>Responsive design</li>
</ul>
<h3 style="margin-top: 2rem; margin-bottom: 1rem;">Technologies Used</h3>
<p>This project uses only vanilla web technologies - HTML5, CSS3, and JavaScript (ES6+). No dependencies or
build tools required!</p>
</div>
</div>
<!-- Contact View -->
<div id="contact" class="view">
<div class="card">
<h2>Contact Us</h2>
<p>Have questions? Send us a message!</p>
<form id="contactForm" style="margin-top: 2rem;">
<input type="text" id="name" placeholder="Your Name" required>
<input type="email" id="email" placeholder="Your Email" required>
<textarea id="message" rows="5" placeholder="Your Message" required></textarea>
<button type="submit">Send Message</button>
</form>
<div id="formMessage" style="margin-top: 1rem; padding: 1rem; border-radius: 4px; display: none;"></div>
</div>
</div>
</main>
<footer>
<p>&copy; 2026 My Simple SPA. Built with ❤️ using vanilla JavaScript.</p>
</footer>
<script>
// Router functionality
class Router {
constructor() {
this.routes = {};
this.currentRoute = null;
// Listen for hash changes
window.addEventListener('hashchange', () => this.handleRoute());
// Handle initial load
this.handleRoute();
}
addRoute(path, handler) {
this.routes[path] = handler;
}
handleRoute() {
const hash = window.location.hash.slice(1) || 'home';
// Hide all views
document.querySelectorAll('.view').forEach(view => {
view.classList.remove('active');
});
// Remove active class from all nav links
document.querySelectorAll('.nav-link').forEach(link => {
link.classList.remove('active');
});
// Show current view
const view = document.getElementById(hash);
if (view) {
view.classList.add('active');
this.currentRoute = hash;
}
// Add active class to current nav link
const activeLink = document.querySelector(`a[href="#${hash}"]`);
if (activeLink) {
activeLink.classList.add('active');
}
// Execute route handler if exists
if (this.routes[hash]) {
this.routes[hash]();
}
}
}
// Initialize router
const router = new Router();
// Add route handlers
router.addRoute('home', () => {
console.log('Home page loaded');
});
router.addRoute('about', () => {
console.log('About page loaded');
});
router.addRoute('contact', () => {
console.log('Contact page loaded');
});
// Handle form submission
document.getElementById('contactForm').addEventListener('submit', (e) => {
e.preventDefault();
const name = document.getElementById('name').value;
const email = document.getElementById('email').value;
const message = document.getElementById('message').value;
// Show success message
const formMessage = document.getElementById('formMessage');
formMessage.style.display = 'block';
formMessage.style.background = '#d4edda';
formMessage.style.color = '#155724';
formMessage.style.border = '1px solid #c3e6cb';
formMessage.textContent = `Thank you, ${name}! Your message has been received. We'll get back to you at ${email} soon.`;
// Reset form
e.target.reset();
// Hide message after 5 seconds
setTimeout(() => {
formMessage.style.display = 'none';
}, 5000);
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment