Skip to content

Simpaisa Frontend Standards & Microfrontend Architecture

Date: 2026-04-03 Owner: CDO Scope: All web assets, portals, sites, and pages across Simpaisa


1. Design Tokens (Single Source of Truth)

All web properties MUST consume tokens from @simpaisa/design-tokens. No hardcoded colours, fonts, or spacing values in any project.

Brand Colours (derived from simpaisa.com production site)

/* Primary — Simpaisa Blue (from website gradient and CTAs) */
--sp-primary:       #0156FC;    /* Primary brand blue — buttons, links, accents */
--sp-primary-dark:  #243E90;    /* Gradient start, header backgrounds */
--sp-primary-bright: #1F6BFF;   /* Highlights, underlines, focus rings */

/* Gradient — used for header bar, primary buttons, hero sections */
--sp-gradient:      linear-gradient(90deg, #243E90 0%, #0156FC 100%);

/* Text */
--sp-text:          #3A3A3A;    /* Primary body text */
--sp-text-secondary: #5B5B5B;   /* Secondary/description text */

/* Semantic */
--sp-success:       #10b981;    /* Completed, active, healthy */
--sp-warning:       #f59e0b;    /* Pending, on_hold, degraded */
--sp-danger:        #FD4A51;    /* Failed, error, critical (from website) */
--sp-info:          #0156FC;    /* Information, processing (same as primary) */

/* Neutral */
--sp-grey-50:       #FBFCFC;    /* Page background (from website body) */
--sp-grey-100:      #F6F6F6;    /* Section backgrounds */
--sp-grey-200:      #EAEAEA;    /* Borders, dividers (from website) */
--sp-grey-300:      #DDDDDD;    /* Secondary borders */
--sp-grey-400:      #8591A9;    /* Form focus state (from website) */
--sp-grey-500:      #5B5B5B;    /* Secondary text */
--sp-grey-600:      #4b5563;
--sp-grey-700:      #374151;
--sp-grey-800:      #1f2937;
--sp-grey-900:      #3A3A3A;    /* Primary text (from website) */

/* Surface */
--sp-surface:         #FBFCFC;    /* Page background (website body bg) */
--sp-surface-raised:  #FFFFFF;    /* Cards, panels */
--sp-surface-overlay: rgba(0,0,0,0.5);  /* Modal backdrops */
--sp-border:          #EAEAEA;    /* Borders, dividers */

Typography (from simpaisa.com — Poppins)

/* Font family — Poppins is the Simpaisa brand font */
--sp-font-sans:   'Poppins', system-ui, -apple-system, sans-serif;
--sp-font-mono:   'JetBrains Mono', 'Fira Code', monospace;
/* NOTE: Only load weights 400, 500, 600, 700 (website loads all 9 — wasteful) */

/* Scale */
--sp-text-xs:     0.75rem;    /* 12px — captions, badges */
--sp-text-sm:     0.875rem;   /* 14px — secondary text, table cells */
--sp-text-base:   1rem;       /* 16px — body text */
--sp-text-lg:     1.125rem;   /* 18px — lead text */
--sp-text-xl:     1.25rem;    /* 20px — section headers */
--sp-text-2xl:    1.5rem;     /* 24px — page titles */
--sp-text-3xl:    1.875rem;   /* 30px — hero titles */
--sp-text-4xl:    2.25rem;    /* 36px — landing page hero */

/* Weight */
--sp-font-normal:  400;
--sp-font-medium:  500;
--sp-font-semibold: 600;
--sp-font-bold:    700;

/* Line height */
--sp-leading-tight:  1.25;
--sp-leading-normal: 1.5;
--sp-leading-relaxed: 1.75;

Spacing Scale

/* 4px base unit */
--sp-space-1:   0.25rem;    /* 4px */
--sp-space-2:   0.5rem;     /* 8px */
--sp-space-3:   0.75rem;    /* 12px */
--sp-space-4:   1rem;       /* 16px */
--sp-space-5:   1.25rem;    /* 20px */
--sp-space-6:   1.5rem;     /* 24px */
--sp-space-8:   2rem;       /* 32px */
--sp-space-10:  2.5rem;     /* 40px */
--sp-space-12:  3rem;       /* 48px */
--sp-space-16:  4rem;       /* 64px */

Shadows

--sp-shadow-sm:   0 1px 2px rgba(0,0,0,0.05);
--sp-shadow-md:   0 4px 6px -1px rgba(0,0,0,0.1);
--sp-shadow-lg:   0 10px 15px -3px rgba(0,0,0,0.1);
--sp-shadow-xl:   0 20px 25px -5px rgba(0,0,0,0.1);

Border Radius

--sp-radius-sm:   0.25rem;   /* 4px — badges, chips */
--sp-radius-md:   0.375rem;  /* 6px — buttons, inputs */
--sp-radius-lg:   0.5rem;    /* 8px — cards, panels */
--sp-radius-xl:   0.75rem;   /* 12px — modals, large cards */
--sp-radius-full: 9999px;    /* Circles, pills */

2. Component Library (@simpaisa/ui)

Architecture: Web Components + Astro Wrappers

Components are built as framework-agnostic Web Components (using Lit or vanilla custom elements) with thin Astro wrappers for the portal. This ensures:

  • Same components work in Astro portals, Cloudflare Workers, static marketing pages, and any future framework
  • No framework lock-in
  • Native browser support, no hydration cost for simple components
  • Astro islands for interactive components (forms, tables, charts)

Component Tiers

Tier 1 — Atoms (no state, pure presentation) - sp-button — primary, secondary, danger, ghost, outline, link variants. Sizes: sm, md, lg - sp-badge — status indicators with semantic colour mapping - sp-icon — SVG icon wrapper from Simpaisa icon set - sp-avatar — user/merchant avatar with fallback initials - sp-spinner — loading indicator - sp-tag — removable label/chip - sp-divider — horizontal/vertical separator

Tier 2 — Molecules (minimal state) - sp-input — text, email, password, number, search with label, error, helper text - sp-select — dropdown with search, multi-select support - sp-textarea — multiline input - sp-checkbox, sp-radio, sp-toggle — boolean/choice inputs - sp-date-picker — date and date-range selection - sp-file-upload — drag-and-drop file upload - sp-toast — notification toast (success, error, warning, info) - sp-tooltip — hover/focus information - sp-breadcrumbs — navigation trail - sp-pagination — cursor-based page controls - sp-stat-card — metric with label, value, trend

Tier 3 — Organisms (stateful, interactive) - sp-data-table — sortable, filterable, paginated table with row actions - sp-form — validated form with submit handling - sp-modal — dialog overlay with focus trap - sp-sidebar — collapsible navigation sidebar - sp-command-palette — Cmd+K search/action palette - sp-chart — line, bar, pie (wrapper around lightweight chart lib) - sp-code-block — syntax-highlighted code with copy button - sp-timeline — event/audit trail display

Tier 4 — Templates (page layouts) - sp-dashboard-layout — sidebar + header + content + footer - sp-public-layout — header + content (no sidebar) - sp-auth-layout — centred card for login/register - sp-docs-layout — sidebar TOC + content + on-page nav

Component API Contract

Every component MUST: 1. Accept design tokens via CSS custom properties (not hardcoded values) 2. Support dark class on a parent element for dark mode 3. Be keyboard accessible (WCAG 2.1 AA) 4. Have a data-testid attribute for testing 5. Emit standard DOM events (not framework-specific) 6. Work without JavaScript for core content (progressive enhancement)


3. Microfrontend Architecture

Composition Model: Build-Time Integration

Phoenix uses build-time composition via Astro, not runtime module federation. Each portal is a separate Astro project that imports from the shared package:

@simpaisa/design-tokens    →  CSS custom properties, Tailwind preset
@simpaisa/ui               →  Web Components + Astro wrappers
@simpaisa/api-client       →  Typed Phoenix API client (shared lib/api.ts)
@simpaisa/auth             →  Shared auth utilities (shared lib/auth.ts)

Why Build-Time Over Runtime

  • Simpler: No module federation, no shared runtime, no version conflicts
  • Faster: Static assets from Cloudflare Pages CDN, no runtime loading
  • Safer: Each portal is independently deployable and testable
  • Astro: Islands architecture handles interactive sections without full SPA overhead

Portal Projects (separate Astro apps, shared packages)

phoenix/
├── packages/
│   ├── design-tokens/     # CSS variables, Tailwind preset
│   ├── ui/                # Web Components + Astro wrappers
│   ├── api-client/        # Typed Phoenix API client
│   └── auth/              # Shared auth utilities
├── portal/                # Staff/Admin + Merchant portal (current)
├── portal-developers/     # Developer portal (public, mostly static)
└── portal-marketing/      # Marketing site (future, fully static)

Shared Tailwind Preset

All portals import the same Tailwind preset so utility classes produce identical output:

// packages/design-tokens/tailwind-preset.mjs
// Derived from simpaisa.com production website
export default {
  theme: {
    extend: {
      colors: {
        primary: { DEFAULT: '#0156FC', dark: '#243E90', bright: '#1F6BFF' },
        surface: { DEFAULT: '#FBFCFC', raised: '#FFFFFF', muted: '#F6F6F6' },
        border:  { DEFAULT: '#EAEAEA', light: '#DDDDDD', focus: '#8591A9' },
        text:    { DEFAULT: '#3A3A3A', secondary: '#5B5B5B' },
        danger:  '#FD4A51',
        success: '#10b981',
        warning: '#f59e0b',
      },
      fontFamily: {
        sans: ['Poppins', 'system-ui', 'sans-serif'],  // Simpaisa brand font
        mono: ['JetBrains Mono', 'Fira Code', 'monospace'],
      },
      borderRadius: { sm: '6px', DEFAULT: '8px', lg: '12px' },
      boxShadow: {
        card: '0px 7.17px 30.75px 0px rgba(9,14,24,0.1)',
        header: '0px 2px 44px 0px rgba(12,18,35,0.06)',
      },
      container: { center: true, padding: '20px', screens: { xl: '1320px' } },
    },
  },
  plugins: [require('@tailwindcss/forms')],
}

Each portal's tailwind.config.mjs:

import simpaisaPreset from '@simpaisa/design-tokens/tailwind-preset.mjs'
export default { presets: [simpaisaPreset], content: ['./src/**/*.{astro,ts}'] }


4. Coding Standards

File Naming

  • Components: PascalCase.astro (Astro), sp-kebab-case.ts (Web Components)
  • Pages: kebab-case.astro or [param].astro for dynamic routes
  • Utilities: camelCase.ts
  • Tests: *.test.ts

TypeScript

  • Strict mode always ("strict": true)
  • No any — use unknown and narrow
  • Interface over type for object shapes
  • Enum for fixed sets (status codes, operator types)

CSS / Tailwind

  • Use design tokens (never hardcode colours/spacing)
  • Prefer Tailwind utilities over custom CSS
  • Custom CSS only for animations or complex layouts
  • Dark mode via dark: prefix (class strategy)
  • No !important — ever

Accessibility

  • All interactive elements: keyboard navigable
  • All images: alt text
  • All forms: <label> associations
  • Colour contrast: WCAG 2.1 AA minimum (4.5:1 for text)
  • Focus indicators: visible and consistent (--sp-teal ring)
  • ARIA attributes where semantic HTML is insufficient

Performance

  • No JavaScript for content that doesn't need it (Astro default)
  • Images: WebP/AVIF with <picture> fallbacks
  • Fonts: font-display: swap, subset Inter to Latin
  • Bundle: <100KB JS per page (excluding charts)
  • Lighthouse target: >90 on all categories

Testing

  • Components: visual regression (Playwright screenshots)
  • Integration: Playwright for critical flows (login, transaction search)
  • Accessibility: axe-core automated checks

5. Status Badge Colour Mapping (Global Standard)

All portals MUST use the same colour for the same status:

Status Colour Token Used In
active, completed, disbursed, delivered, healthy Green --sp-success All
initiated, created, pending, open Blue --sp-info All
processing, awaiting_authorisation, awaiting_3ds Blue (pulse) --sp-info + animation All
on_hold, in_review, degraded, warning Amber --sp-warning All
failed, rejected, dead_letter, critical, error Red --sp-danger All
cancelled, deactivated, suspended, voided Grey --sp-grey-400 All
reversed, refunded, partially_refunded Purple #8b5cf6 Transactions

6. URL Structure Convention

All portals follow the same URL hierarchy:

/                           →  Landing / redirect
/login                      →  Authentication
/dashboard                  →  Overview / home
/dashboard/transactions     →  Transaction list
/dashboard/transactions/:id →  Transaction detail
/dashboard/merchants        →  Merchant list (admin only)
/dashboard/merchants/:id    →  Merchant detail
/dashboard/operators        →  Operator management
/dashboard/webhooks         →  Webhook deliveries
/dashboard/config           →  Feature flags & config
/dashboard/settings         →  User/system settings
/developers                 →  Developer portal (public)
/developers/docs            →  API reference
/developers/sandbox         →  Test environment
/api/auth/*                 →  Auth API routes (server-side)

7. Dark Mode

All portals MUST support dark mode:

  • Toggled via class on <html> element (class="dark")
  • User preference stored in cookie (persists across sessions)
  • Respects prefers-color-scheme on first visit
  • All components use dark: Tailwind variants
  • Charts and data visualisations adapt to dark mode
  • No white flashes on page load (inline script sets class before render)

8. Internationalisation (i18n) — Future Ready

Not required for launch, but design for it:

  • All user-facing strings in a separate locale file (not inline in components)
  • Date/time formatting via Intl.DateTimeFormat (never manual formatting)
  • Number formatting via Intl.NumberFormat (respects locale)
  • Currency display via Intl.NumberFormat with style: 'currency'
  • RTL support via dir attribute (for future Arabic/Urdu markets)
  • No string concatenation for sentences — use template interpolation

9. Deployment Standard

All portals deploy to Cloudflare Pages:

Production:    portal.simpaisa.com      (staff + merchant dashboard)
Staging:       staging.portal.simpaisa.com
Preview:       {branch}.portal.pages.dev (automatic per PR)

Developer:     developers.simpaisa.com  (public, static)
Marketing:     www.simpaisa.com         (future)

Each portal has its own wrangler.toml with: - Cloudflare Pages project name - Environment variables (PHOENIX_API_URL) - Build command and output directory - Custom headers (CSP, HSTS, X-Frame-Options)