JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 445
  • Score
    100M100P100Q95593F
  • License MIT

Embeddable DigiPin-powered smart address checkout widget for Indian e-commerce

Package Exports

  • @quantaroute/checkout
  • @quantaroute/checkout/dist/style.css

Readme

@quantaroute/checkout

DigiPin-powered smart address checkout widget for Indian e-commerce. Two-step: Map pin → Auto-filled form. Works in any React/Next.js/Nuxt/Vite app.

Made in India DigiPin Map License


What it does

Replaces your broken Indian address form with a two-step Uber-style flow:

Step 1 – Map Pin                    Step 2 – Auto-fill + Details
┌──────────────────────────┐        ┌──────────────────────────┐
│  [DigiPin: 39J-438-TJC7] │        │  📍 Auto-detected         │
│                           │        │  State:    Delhi          │
│    🗺 Carto Positron map  │  ──►  │  District: New Delhi     │
│         📍 ← drag         │        │  Pincode:  110011         │
│                           │        │  ✓ Deliverable            │
│  [📡 Locate Me]           │        │  🏠 Add details           │
│  [Confirm Location →]     │        │  Flat No:  [_________]    │
└──────────────────────────┘        │  [← Adjust] [Save ✓]    │
                                     └──────────────────────────┘

Key features:

  • DigiPin shown offline in real-time as the user drags the pin (~4m×4m precision)
  • No Google Maps. Free Carto Positron vector basemap (MapLibre GL JS)
  • Auto-fills State, District, Locality, Pincode, Delivery status from QuantaRoute API
  • Manual fields: Flat no., Floor, Building (OSM-pre-filled), Street/Area (OSM-pre-filled)
  • Mobile-first (full-screen on phones, card on desktop)
  • Dark mode, reduced-motion, keyboard navigation, ARIA labels
  • TypeScript, zero runtime deps beyond MapLibre + React

Quick start

0 · Get an API key

  1. Sign up at developers.quantaroute.com
  2. Create a project → copy your API key
  3. Store it as an environment variable in your app:
Framework Variable name convention
Next.js NEXT_PUBLIC_QUANTAROUTE_KEY in .env.local
Vite VITE_QR_API_KEY in .env
Nuxt NUXT_PUBLIC_QR_API_KEY in .env
Node/Express backend QUANTAROUTE_KEY (server-side only)

Never hard-code or commit API keys to git.


1 · Install

npm install @quantaroute/checkout maplibre-gl
# or
yarn add @quantaroute/checkout maplibre-gl

2 · Import CSS

// In your app's entry file (main.tsx / _app.tsx / nuxt.config.ts, etc.)
import 'maplibre-gl/dist/maplibre-gl.css';
import '@quantaroute/checkout/dist/style.css';

3 · Drop it in

import { CheckoutWidget } from '@quantaroute/checkout';

export default function CheckoutPage() {
  return (
    <CheckoutWidget
      apiKey={process.env.NEXT_PUBLIC_QUANTAROUTE_KEY!}  {/* never hard-code keys */}
      onComplete={(address) => {
        console.log(address.digipin);          // "39J-438-TJC7"
        console.log(address.pincode);          // "110011"
        console.log(address.formattedAddress); // "Flat 4B, Floor 3rd, ..."
        // → send to your backend / payment gateway
      }}
    />
  );
}

Get your API key (free tier: 25,000 requests/month) → developers.quantaroute.com

Store it as an environment variable — never commit API keys to source control.


Props

Prop Type Default Description
apiKey string required QuantaRoute API key
onComplete (addr: CompleteAddress) => void required Fired after user saves address
apiBaseUrl string https://api.quantaroute.com Custom API URL (self-hosted)
onError (err: Error) => void Optional error handler
defaultLat number India center Pre-center the map here
defaultLng number India center Pre-center the map here
theme 'light' | 'dark' 'light' Color theme
mapHeight string '380px' CSS height of the map area
title string 'Add Delivery Address' Widget header text
className string Extra class on root element
style CSSProperties Inline styles on root element

CompleteAddress output

interface CompleteAddress {
  digipin: string;          // "39J-438-TJC7"
  lat: number;              // 28.61390
  lng: number;              // 77.20900

  // Auto-filled from QuantaRoute API
  state: string;            // "Delhi"
  district: string;         // "New Delhi"
  division: string;         // "New Delhi Central"
  locality: string;         // "Nirman Bhawan SO"
  pincode: string;          // "110011"
  delivery: string;         // "Delivery" | "Non Delivery"
  country: string;          // "India"

  // Manual entry by user
  flatNumber: string;       // "4B"
  floorNumber: string;      // "3rd"
  buildingName: string;     // "Sunshine Apartments" (pre-filled from Nominatim OSM)
  streetName: string;       // "MG Road, Action Area I" (pre-filled from road + suburb)

  formattedAddress: string; // "4B, 3rd Floor, Sunshine Apartments, MG Road, ..."
}

Framework integration guides

Next.js (App Router)

// app/checkout/page.tsx
'use client';                         // ← required (MapLibre is browser-only)

import dynamic from 'next/dynamic';

const CheckoutWidget = dynamic(
  () => import('@quantaroute/checkout').then((m) => m.CheckoutWidget),
  { ssr: false }                      // ← required (no SSR for map)
);

export default function CheckoutPage() {
  return (
    <main className="max-w-lg mx-auto p-4">
      <CheckoutWidget
        apiKey={process.env.NEXT_PUBLIC_QUANTAROUTE_KEY!}   {/* set in .env.local */}
        onComplete={(addr) => console.log(addr)}
      />
    </main>
  );
}

Add CSS imports to app/layout.tsx:

import 'maplibre-gl/dist/maplibre-gl.css';
import '@quantaroute/checkout/dist/style.css';

Next.js (Pages Router)

// pages/checkout.tsx
import dynamic from 'next/dynamic';
const CheckoutWidget = dynamic(() => import('@quantaroute/checkout'), { ssr: false });

export default function CheckoutPage() {
  return (
    <CheckoutWidget
      apiKey={process.env.NEXT_PUBLIC_QUANTAROUTE_KEY!}  {/* .env.local */}
      onComplete={(a) => console.log(a)}
    />
  );
}

Nuxt 3

// nuxt.config.ts
export default defineNuxtConfig({
  css: [
    'maplibre-gl/dist/maplibre-gl.css',
    '@quantaroute/checkout/dist/style.css',
  ],
});
<!-- components/AddressWidget.client.vue -->
<!-- The .client suffix ensures this only renders on the client -->
<script setup lang="ts">
import { CheckoutWidget } from '@quantaroute/checkout';

function handleComplete(address) {
  console.log(address.digipin, address.formattedAddress);
}
</script>

<template>
  <!-- API key via runtimeConfig → useRuntimeConfig().public.qrApiKey -->
  <CheckoutWidget
    :api-key="runtimeConfig.public.qrApiKey"
    map-height="360px"
    @complete="handleComplete"
  />
</template>

Vite + React

// src/App.tsx
import 'maplibre-gl/dist/maplibre-gl.css';
import '@quantaroute/checkout/dist/style.css';
import { CheckoutWidget } from '@quantaroute/checkout';

function App() {
  return (
    <div style={{ padding: '20px' }}>
      <CheckoutWidget
        apiKey={import.meta.env.VITE_QR_API_KEY}
        onComplete={(addr) => console.log('Saved:', addr)}
      />
    </div>
  );
}

Vanilla JS (UMD / Script tag)

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://unpkg.com/maplibre-gl/dist/maplibre-gl.css" />
  <link rel="stylesheet" href="https://unpkg.com/@quantaroute/checkout/dist/style.css" />
</head>
<body>
  <div id="checkout-root"></div>

  <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
  <script src="https://unpkg.com/@quantaroute/checkout/dist/lib/quantaroute-checkout.umd.js"></script>
  <script>
    const { createRoot } = ReactDOM;
    const { CheckoutWidget } = QuantaRouteCheckout;

    // Replace window.__QR_API_KEY__ with your key from developers.quantaroute.com
    // In production, inject this via server-side template or env variable.
    createRoot(document.getElementById('checkout-root')).render(
      React.createElement(CheckoutWidget, {
        apiKey: window.__QR_API_KEY__ || '',
        onComplete: (addr) => console.log('Done:', addr),
      })
    );
  </script>
</body>
</html>

React Native (coming soon)

A React Native version is planned that will use react-native-maps + the same offline DigiPin algorithm and QuantaRoute API. Track progress in issues.


Advanced usage

Use sub-components individually

import { MapPinSelector, AddressForm, getDigiPin, isWithinIndia } from '@quantaroute/checkout';

// Offline DigiPin (no API call needed)
const dp = getDigiPin(28.6139, 77.2090); // "39J-438-TJC7"
const valid = isWithinIndia(28.6139, 77.2090); // true

// Custom two-step flow
function MyCheckout() {
  const [loc, setLoc] = useState(null);

  return loc == null
    ? <MapPinSelector onLocationConfirm={(lat, lng, dp) => setLoc({ lat, lng, dp })} />
    : <AddressForm {...loc} digipin={loc.dp} apiKey="..." onAddressComplete={...} onBack={...} />;
}

Custom theme with CSS variables

/* Override the design tokens in your global CSS */
.qr-checkout {
  --qr-primary:      #6366f1;   /* indigo */
  --qr-primary-dark: #4f46e5;
  --qr-radius:       8px;
  --qr-font:         'Poppins', sans-serif;
}

Map tile license

This widget uses Carto Positron vector tiles via MapLibre GL JS.

  • Free for commercial use (attribution required)
  • Attribution: © OpenStreetMap contributors © CARTO
  • Does not use Google Maps, Mapbox, or OSM raster tiles
  • No API key required for Carto basemaps

DigiPin license

The offline DigiPin algorithm is the official India Post implementation:


Development

git clone https://github.com/quantaroute/checkout.git
cd quantaroute-checkout

npm install
npm run dev        # Dev server at http://localhost:5173

npm run type-check # TypeScript check
npm run build      # Build demo
npm run build:lib  # Build library (dist/lib/)

Changelog

v1.0.0

  • Initial release
  • MapLibre GL + Carto Positron (free, no API key)
  • Offline DigiPin generation (real-time on pin drag)
  • QuantaRoute location lookup API integration
  • Mobile-first responsive design
  • Dark mode, reduced-motion, keyboard accessible
  • React / Next.js / Nuxt / Vite / Vanilla JS support

Made with ❤️ in India · Powered by QuantaRoute