DEV Community

Karthik Gs
Karthik Gs

Posted on

Why I Built Cartlify — A Production-Ready E-commerce UI Kit for React

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

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

✅ 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)}
/>
Enter fullscreen mode Exit fullscreen mode

⏳ 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 hooksuseCart, 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
Enter fullscreen mode Exit fullscreen mode

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

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

Clean path aliases so no ../../ imports anywhere:

import { Button } from '@primitives/Button';
import { useCart } from '@hooks/useCart';
import type { Product } from '@types';
Enter fullscreen mode Exit fullscreen mode

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)