By Faiz Ullah — Full-Stack Developer & Founder of DG Technology
Every e-commerce build I'd done before reached for React almost by reflex. So when I built JKMart — a grocery and pansar (spice/herb) store — I deliberately went the other way: no framework, no build step, no dependencies. Just HTML, CSS, and vanilla JavaScript.
It forced me to relearn fundamentals that frameworks quietly hide from you. Here's what stood out.
State Management Without a Framework
React trains you to think "state lives in a component, re-render on change." Without that abstraction, you have to build the same discipline by hand. I centralized everything — products, categories, cart, site settings — into one structured data store, and treated every UI update as "read from the store, write back to the store, re-render the affected DOM section."
const store = {
products: [...],
cart: [],
addToCart(id) {
this.cart.push(id);
renderCart(); // explicit, not automatic
}
};
The difference from React: nothing happens automatically. Every single re-render is a function you call yourself. It's more typing, but it also means there's no mystery about why something on screen updated — you can trace it line by line.
The Cart Has to Survive a Refresh
A cart that empties itself when the customer accidentally refreshes the page is a lost sale. With no backend session and no framework state layer, persistence comes down to localStorage directly:
function saveCart() {
localStorage.setItem('cart', JSON.stringify(store.cart));
}
function loadCart() {
store.cart = JSON.parse(localStorage.getItem('cart') || '[]');
}
It's a small thing, but it's the kind of detail that separates a demo from something that actually works the way a shopper expects.
Search That Feels Instant
Live product search needs to filter as the user types, not after they hit Enter. The naive version re-filters the entire product list on every keystroke, which is fine for a small catalog but teaches a bad habit. I built it to debounce input and search across multiple fields (name, category, tags) at once, so it stayed fast and felt forgiving of partial or imprecise queries.
Depth Without a 3D Library
I wanted product cards to feel tactile — a subtle tilt that responds to the cursor, the kind of detail that makes a static catalog feel alive. Rather than reaching for a 3D library, this is just trigonometry on mouse position relative to the card's center:
card.addEventListener('mousemove', (e) => {
const rect = card.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width - 0.5;
const y = (e.clientY - rect.top) / rect.height - 0.5;
card.style.transform = `perspective(800px) rotateY(${x * 10}deg) rotateX(${-y * 10}deg)`;
});
No dependency, no bundle size cost — just a few lines of CSS transform math.
An Admin Panel That's Also Just HTML
The admin panel — product management, category editing, site settings — is built the exact same way as the storefront: vanilla JS reading and writing the same data store, just rendering a different UI on top of it. There's no separate "admin framework." It's the same toolkit, pointed at a different audience.
When Not Reaching for a Framework Actually Makes Sense
This isn't an argument that frameworks are bad — for an app with deep nested state and dozens of interacting components, React earns its complexity. But for a focused storefront like this:
- Zero build step means the entire site is editable and previewable by just opening the file
-
Zero dependencies means no
npm auditsurprises, no version upgrades breaking things a year later - Instant load — there's no JS bundle to download and parse before the page becomes interactive
For a project of this scope, that trade-off was worth it.
What I'd Tell Someone Building Their First Vanilla JS Project
- Centralize your state into one object, even without a framework forcing you to. Scattered global variables are where bugs breed.
-
Persist anything the user would be annoyed to lose — cart contents, form drafts — to
localStorageimmediately, not just on submit. - Debounce expensive operations like search filtering, even in a small app. It's a habit worth having by default.
- Don't assume you need a library for interaction polish. A lot of "wow" details are a few lines of math.
The Stack
| Layer | Technology |
|---|---|
| Structure | Semantic HTML5 |
| Styling | Custom CSS3, gradients & animations |
| Logic | Vanilla JavaScript (ES6+) |
| Persistence | localStorage |
| Build | None |
Faiz Ullah
Frontend Developer · Full-Stack Engineer · Founder of DG Technology
🌐 faizullah.pk · 💻 github.com/faizullahpk/ecommerce-store-demo
Curious about when to reach for a framework and when not to? Follow along — I write about practical, real-world full-stack decisions.
Top comments (0)