Platform app · 5 min read
Cardify: restyling a storefront's product cards without touching its code
A drop-in app for the Ratio platform, live on 16 storefronts. A merchant flips one switch and the storefront's product cards are replaced by one of five designs, safely and with no reload.
- Lit
- Fastify
- MySQL
- React
- Playwright
Merchants on a commerce platform often want a different look for their product cards, but changing card markup means touching every widget that renders one: collection grids, carousels, search results and related products. I built Cardify as an app that does it from the outside. The merchant picks a design in an admin screen, and the storefront's own cards are swapped live.
Setup
- Merchant adminReact + Vite. Switch on, pick a design and colours
- Settings APIFastify + MySQL. Admin writes are key-protected
- Public configRead-only endpoint the storefront loader calls
On the storefront
- Tiny loader0.5 KB gzipped. Fetches the config
- Config says off?Do nothing. Native cards stay
- Load widgetAbout 10 KB gzipped, imported lazily
- OverlayHide each native card, mount a Cardify card in its cell
When a shopper clicks
- Cardify cardClick or quick-buy
- Hidden native linkThe click is delegated to the store's own element
- Store behaviour runsRouting, quick-buy popup and analytics, unchanged
Design choices that matter
- Purely cosmetic. A card uses exactly the data the native card already renders, so there is no new data contract for the storefront to maintain.
- Native cards are hidden, never removed. The overlay mounts inside the same cell, so the store's grid and carousel layout is untouched, and a MutationObserver picks up cards that appear later.
- Behaviour is delegated back to the host. Clicking a Cardify card clicks the hidden native link, so the store's own routing, popups and tracking keep running.
- It fails safe. If the backend is down, the config call errors or the bundle is blocked, the shopper simply sees the original cards.
- No polling. The config refreshes on page load and when the tab regains focus. A timer would make every visitor's tab hit the backend.
- The server refuses to start without an admin key, so a missing setting can never mean an open admin.
Five designs, one structure
Classic, minimal, overlay, hover-reveal and editorial all share one DOM structure and differ only in CSS. That is why click and quick-buy bridging works for every design for free. Merchants can tune accent, text and background colours, corner radius, image shape and toggles for the badge, quick-buy, rating and compare-at price, all validated with a shared zod schema. Adding a sixth design is a registry entry plus one CSS block.
Status: live in production on 16 storefronts on the Ratio platform, backed by unit tests and a headless-Chromium end-to-end suite.