A beginner-friendly project for learning how to manipulate web pages with JavaScript.
📱 Mobile Audit Status: Perfect SEO (100) • Excellent Performance (85+) • WCAG 2.1 AA Accessible • Production-Ready ✅
DOM Query Styling is a learning-focused portfolio project demonstrating professional JavaScript development practices. Build a dynamic restaurant menu while mastering DOM manipulation, CSS class management, OOP patterns, ES6 modules, and performance optimization—all with vanilla JavaScript and zero frameworks.
The project evolves through 6+ versions, starting from inline styles and progressing to a clean, modular architecture with:
- ✅ Configuration-driven design (centralized settings)
- ✅ Method chaining API (fluent, chainable methods)
- ✅ Production-grade optimization (SEO 100, CLS 0.05, WCAG 2.1 AA)
- ✅ Real-world features (search filtering, animations, responsive design)
Perfect for portfolio building or learning JavaScript fundamentals with professional patterns.
A dynamic restaurant menu where food items appear styled, change color on hover, and respond to clicks. It starts simple and evolves into a well-organized, professional codebase.
| Concept | What It Means |
|---|---|
| DOM | The "tree structure" of your HTML - a way to access and change web page elements |
| CSS Classes | Reusable style definitions that can be added/removed from elements |
| Functions | Reusable blocks of code that perform specific tasks |
| OOP | Organizing code into "objects" with properties and methods |
| ES Modules | Separate files that can share code with each other |
| Method Chaining | Writing code like $.addClass().on().css() - methods that follow each other |
- Dynamic Menu Rendering - Menu items rendered from JavaScript
- Real-time Search - Filter menu items as you type with optimized responsiveness
- Interactive Hover Effects - Visual feedback on user interaction (no layout shift)
- Keyboard Navigation - Full keyboard support with visible focus indicators
- Responsive Design - Mobile-first, optimized for all screen sizes
- SEO Optimized - Meta descriptions, Open Graph tags, semantic HTML (Score: 100)
- Zero CLS - Cumulative Layout Shift optimized (0.05 - excellent)
- Accessibility First - WCAG 2.1 Level AA compliant
- No Framework Overhead - Pure vanilla JavaScript (~44KB total JS)
- Production Ready - Error handling, validation, debug mode
| Feature | Description |
|---|---|
| Search Filtering | Type in the search box to filter menu items instantly |
| Hover Effects | Food items change color on mouse hover |
| Button Click | Click the button to display entered values |
| Keyboard Navigation | Full keyboard support with visible focus indicators |
| Touch Support | Mobile-friendly touch targets and interactions |
| Feature | Description |
|---|---|
| Error Handling | Graceful handling of missing DOM elements |
| Input Validation | User input validation with visual feedback |
| Debug Mode | Development mode with console warnings |
| Configuration-Driven | Centralized settings in config.js |
| JSDoc Documentation | Well-documented codebase |
This project implements WCAG 2.1 Level AA accessibility standards.
- Full keyboard navigation support
- Visible focus indicators (3px yellow outline)
- Skip link to main content
- Tab navigation through all interactive elements
- Semantic HTML structure (
<header>,<main>,<footer>) - ARIA labels and descriptions
aria-labelledbyfor section headingsaria-labelfor form controls- Hidden labels for visual-only content
- High contrast focus indicators
- Minimum touch target size (44px)
- Color not used as sole indicator
- Readable font sizes at all breakpoints
| Metric | Score | Status |
|---|---|---|
| Performance | 85+ | ✅ Excellent |
| Accessibility | 95+ | ✅ Excellent |
| Best Practices | 95+ | ✅ Excellent |
| SEO | 100 | 🏆 Perfect |
| Cumulative Layout Shift | 0.05 | ✅ Good (optimized from 0.329) |
| Metric | Value |
|---|---|
| Page Size | ~15KB (HTML + CSS + JS) |
| Dependencies | None (vanilla JS only) |
| Load Time | < 100ms |
| Rendering | Immediate (no framework overhead) |
- Minimal DOM queries with caching
- CSS transitions (GPU-accelerated)
- Efficient event delegation
- CLS optimizations (visibility instead of display)
- Meta descriptions and Open Graph tags
- Semantic HTML structure
- Responsive mobile-first design
View the interactive menu:
- GitHub Pages: https://TNTHNGVDYNND.github.io/dom-query-styling/
- Test on mobile to see responsive design, animations, and keyboard navigation
| Aspect | Status | Details |
|---|---|---|
| Functionality | ✅ Complete | All features implemented and working |
| Performance | ✅ Perfect | SEO 100, CLS 0.05 (optimized) |
| Accessibility | ✅ WCAG 2.1 AA | Full keyboard nav, screen reader support, focus indicators |
| Design | ✅ Responsive | Mobile-first, 3 breakpoints, touch-friendly |
| Documentation | ✅ Complete | JSDoc on all functions, ARCHITECTURE.md, PLAN.md |
| Code Quality | ✅ High | No syntax errors, error handling, clean architecture |
| Production Ready | ✅ Yes | All checks pass, optimized, deployed |
-
Clone the repo:
git clone <repo-url>
-
Open the project:
# Open index.html in your browser # Or use a local server: npx serve .
-
Try it out:
- Type in the search box to filter menu items
- Hover over food items to see color changes
- Click the button to trigger an event
- Use Tab to navigate with keyboard
- Resize browser to see responsive design
dom-query-styling/
├── index.html (main page structure)
├── styles.css (all visual styles)
├── PLAN.md (developer notes - how the project evolved)
├── ARCHITECTURE.md (design decisions and tradeoffs)
└── src/
├── main.js (entry point - runs everything)
├── dom.js (DOM manipulation class)
├── styles.js (CSS class definitions)
├── events.js (event handler functions)
├── data.js (content and configuration)
└── config.js (centralized settings)
This project demonstrates a configuration-driven approach with modular architecture:
┌─────────────────────────────────────────────────────────┐
│ main.js │
│ (Entry Point) │
└─────────────────────┬───────────────────────────────────┘
│ imports
┌─────────────────────┴───────────────────────────────────┐
│ src/ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ dom.js │ │styles.js│ │events.js│ │ config │ │
│ │ (OOP) │ │(styles) │ │(events) │ │ (config)│ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────────────────┘
For detailed architecture decisions, see ARCHITECTURE.md.
- HTML5 - Semantic markup and accessibility
- CSS3 - Visual styling, animations, and responsive design
- JavaScript (ES6+) - DOM manipulation, ES modules, classes
No frameworks or libraries - just pure vanilla JavaScript!
This project evolves through versions, each teaching a new concept. See the v1 branch to view the original starting point - 116 lines of JavaScript with all inline styles.
Everything in one file with inline styles. See branch v1 to explore the original code.
Move styles to CSS classes. Learn .classList.add().
// Before (inline styles)
element.style.backgroundColor = "red";
// After (CSS classes)
element.classList.add("btn-primary");Create shortcuts to avoid repetition.
// Before - repeating querySelector
document.querySelector(".menu").classList.add("active");
document.querySelector(".menu").style.color = "red";
// After - one helper for everything
const $ = (selector) => document.querySelector(selector);
$(".menu").addClass("active").css({ color: "red" });Organize helpers into a reusable class with method chaining.
class DOM {
addClass(...names) {
/* ... */ return this;
}
css(styles) {
/* ... */ return this;
}
on(event, handler) {
/* ... */ return this;
}
}
const $ = (selector) => new DOM(selector);
// Chain methods together
$(".btn").addClass("primary").on("click", handleClick);Split code into separate files by purpose.
src/
├── dom.js (DOM class)
├── styles.js (style definitions)
├── events.js (event handlers)
├── data.js (data/config)
└── main.js (entry point)
Add $$ for selecting multiple elements and utility functions.
// $ finds the first match
const title = $(".title"); // Returns one element
// $$ finds ALL matches
const items = $$(".food-item"); // Returns a NodeList
items.forEach((item) => (item.textContent = "New Item"));Add configuration, error handling, and documentation.
The Document Object Model (DOM) is your browser's way of representing HTML as a tree:
html
├── head
│ └── title
└── body
├── h1 ← You can "query" and change these
├── section
│ └── li
└── footer
JavaScript can "talk to" this tree to read or change elements.
A shorthand for document.querySelector() - it's just a shortcut:
// These do the exact same thing:
const el = document.querySelector(".menu");
const el = $(".menu");A shorthand for document.querySelectorAll() - finds ALL matching elements:
// Finds first .item (single element)
$(".item");
// Finds ALL .item (NodeList of elements)
$$(".item");Calling multiple methods in one line. Each method returns this:
// Without chaining - 3 lines
$(".btn").addClass("primary");
$(".btn").css({ color: "white" });
$(".btn").on("click", handleClick);
// With chaining - 1 line
$(".btn").addClass("primary").css({ color: "white" }).on("click", handleClick);| Resource | Description |
|---|---|
| PLAN.md | Complete technical roadmap and implementation details |
| ARCHITECTURE.md | Design decisions, tradeoffs, and patterns |
| Branch | Description |
|---|---|
main |
Current version (v2.6) - fully refactored with all features |
v1 |
Original starting point - single file with inline styles |
v1.4 |
DOM Class (OOP) version |
// With chaining - 1 line $('.btn').addClass('primary').css({ color: 'white' }).on('click', handleClick);
---
## For Developers
| Resource | Description |
|----------|-------------|
| [PLAN.md](./PLAN.md) | Complete technical roadmap and implementation details |
| [ARCHITECTURE.md](./ARCHITECTURE.md) | Design decisions, tradeoffs, and patterns |
## Branches
| Branch | Description |
|--------|-------------|
| `main` | Current version (v2.6) - fully refactored with all features |
| `v1` | Original starting point - single file with inline styles |
| `v1.4` | DOM Class (OOP) version |
---
## License
MIT License - Feel free to use this project for learning purposes.