DEV Community

Faizullah
Faizullah

Posted on

I Built a Full E-Commerce Store With Zero Frameworks — Here's What I Learned

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
  }
};
Enter fullscreen mode Exit fullscreen mode

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') || '[]');
}
Enter fullscreen mode Exit fullscreen mode

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)`;
});
Enter fullscreen mode Exit fullscreen mode

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 audit surprises, 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 localStorage immediately, 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)