After 10+ years of rebuilding the same components, I finally packaged them.
The Problem
Every e-commerce project I've worked on — at Fidelity Investments, OCBC Bank, Mondi Group — started the same way.
Day 1: Build the ProductCard.
Day 2: Build the CartDrawer.
Day 3: Wire up the CheckoutStepper.
Day 4: Fix accessibility issues.
Day 5: Write tests.
And then repeat on the next project.
After doing this enough times, I realized: this is wasted time. These components don't change much between projects. The logic is always the same. The accessibility requirements are always the same. The edge cases are always the same.
So I built Cartlify — a React + TypeScript + Tailwind CSS component library specifically for e-commerce UIs.
What's Inside
🛍️ ProductCard
The component every e-commerce app needs on day one.
- 3 layout variants — default (vertical), horizontal, compact
- Image gallery with thumbnail navigation
- Wishlist toggle (filled/outline heart)
- Sale / New / Out of Stock badges
- Star ratings display
- Skeleton loading state with
animate-pulse - Automatic discount % calculation from
originalPrice
<ProductCard
product={product}
variant="default"
showRating={true}
showWishlist={true}
onAddToCart={(p) => addToCart(p)}
onWishlistToggle={(p) => toggleWishlist(p)}
/>
🛒 CartDrawer
A slide-in cart drawer that handles everything out of the box.
- Smooth slide-in from right (or left)
- Focus trap — keyboard stays inside the drawer when open
- ESC key dismisses the drawer
- Quantity stepper with min/max controls
- Empty cart state with custom icon support
- Auto-calculated subtotal
- Fixed header + scrollable items + fixed footer
const { isOpen, onOpen, onClose } = useDisclosure();
<CartDrawer
isOpen={isOpen}
onClose={onClose}
items={cartItems}
onQuantityChange={handleQuantityChange}
onRemoveItem={handleRemove}
onCheckout={handleCheckout}
/>
✅ CheckoutStepper
Multi-step progress indicator for the checkout flow.
- Horizontal and vertical orientations
- Animated connector lines between steps
- Three step states: completed, active, pending
- Click on completed steps to go back
- Custom icons per step
- Keyboard navigation (arrow keys)
<CheckoutStepper
steps={[
{ id: 'cart', label: 'Cart' },
{ id: 'shipping', label: 'Shipping' },
{ id: 'payment', label: 'Payment' },
{ id: 'confirm', label: 'Confirm' },
]}
currentStep={2}
orientation="horizontal"
onStepClick={(index) => setStep(index)}
/>
⏳ PageLoader
4 animation styles (spin, pulse, bounce, dots) with 3 position modes (inline, overlay, fullscreen).
What Else Ships With It
Beyond the 4 components, Cartlify includes:
-
3 utility hooks —
useCart,useDisclosure,useMediaQuery - 11 tree-shakeable icons — cart, heart, star, trash, chevrons, and more
- 40+ CSS design tokens — spacing, colors, radii, shadows
- Full dark mode support out of the box
- Reusable primitives — Button, Badge, IconButton used internally
Built for Real Production Use
I didn't want this to be a demo library. Every decision was made with production in mind:
Testing
141 Jest + React Testing Library tests covering interactions, accessibility, edge cases, and keyboard behavior.
PASS src/components/CartDrawer/CartDrawer.test.tsx
PASS src/components/ProductCard/ProductCard.test.tsx
PASS src/components/CheckoutStepper/CheckoutStepper.test.tsx
Test Suites: 12 passed
Tests: 141 passed
Accessibility
Every component is WCAG 2.1 AA compliant:
-
aria-modal,role="dialog"on CartDrawer -
aria-current="step"on active stepper step -
role="article"on ProductCard - All icon buttons have
aria-label - Full keyboard navigation
TypeScript
Strict mode, zero any. Every prop is typed, every event handler is typed.
interface ProductCardProps {
product: Product;
variant?: 'default' | 'horizontal' | 'compact';
showRating?: boolean;
isWishlisted?: boolean;
onAddToCart: (product: Product) => void;
onWishlistToggle?: (product: Product) => void;
}
Bundler Compatibility
Works with Vite, Next.js, Remix — any modern bundler. Ships as ESM + CJS with .d.ts types via tsup.
Tech Stack
| Layer | Choice |
|---|---|
| Framework | React 18 |
| Language | TypeScript (strict) |
| Styling | Tailwind CSS v3 |
| Documentation | Storybook v7 |
| Testing | Jest + React Testing Library |
| Build | tsup |
| Linting | ESLint + Prettier |
Folder Structure
src/
├── components/
│ ├── ProductCard/
│ ├── CartDrawer/
│ ├── CheckoutStepper/
│ └── PageLoader/
├── primitives/
│ ├── Button/
│ ├── Badge/
│ └── IconButton/
├── hooks/
│ ├── useCart.ts
│ ├── useDisclosure.ts
│ └── useMediaQuery.ts
├── icons/
├── tokens/
└── types/
Clean path aliases so no ../../ imports anywhere:
import { Button } from '@primitives/Button';
import { useCart } from '@hooks/useCart';
import type { Product } from '@types';
Storybook Documentation
Every component has full interactive Storybook stories covering all variants, states, and edge cases. You can explore the live Storybook before buying.
Live demo → https://cartlify.vercel.app/
Get It
Cartlify is available on Gumroad for $29 — one-time payment, single-site license.
🛒 Gumroad → https://karthiksoftengg.gumroad.com/l/cartlify-react-ui-kit
What's Next
Planning to add:
- ProductGrid with filter sidebar
- SearchBar with suggestions
- ReviewCard + RatingInput
- WishlistDrawer
- More design token themes
If there's a component you'd love to see, drop it in the comments — I'll prioritize based on demand.
Built by Karthik G S — Senior Frontend Engineer with 10+ years experience in React, TypeScript and React Native.
Tags: react typescript tailwindcss storybook webdev javascript frontend ecommerce opensource
Top comments (0)