Drop Monigo’s customer portal into your own React, Vue, Svelte, or Flutter app — no iframes, no auth flow to write.
Monigo ships first-class UI packages for React, Vue, Svelte, and Flutter. Each one embeds the full customer portal — invoices, subscriptions, wallets, payout accounts, payment methods — directly in your app, styled to match your brand, with a single portal-token prop.Use these packages when you want the customer experience to live inside your product rather than redirecting to the hosted portal at monigo.co/portal/<token>.
Target
Package
React 18+
@monigo/react
Vue 3.4+
@monigo/vue
Svelte 5
@monigo/svelte
Flutter 3.24+
monigo_portal
All four deliver the same building blocks (invoice list, wallet card, subscription card, etc.) and the same opinionated composed portal (<MonigoPortal />). They share a common core: @monigo/portal-core (typed API client + state machines) and @monigo/tokens (CSS variables and theming helpers).
The TS packages have zero runtime dependencies beyond their peer framework. No CSS-in-JS, no Tailwind, no router lock-in. Monigo’s design tokens ship as plain CSS variables.
import { MonigoClient } from '@monigo/sdk'const monigo = new MonigoClient({ apiKey: process.env.MONIGO_API_KEY! })// In a route authenticated to the current user:const { token } = await monigo.portalTokens.create({ customer_external_id: session.userId, label: 'In-app portal',})// Return `token` to your frontend (e.g. as JSON)
That’s the entire integration. <MonigoPortal /> renders its own navigation, routing, and all feature pages — dashboard, invoices, bills, subscriptions, wallets, payment methods, payout accounts.
If you want the data and behaviour but not the opinionated layout, use the building-block components directly. They share the same <MonigoProvider> context and run independently.
The same component names exist across React, Vue, and Svelte. Flutter widgets follow Dart’s snake_case → Pascal convention (InvoiceList, invoice_list.dart).
Monigo’s components render against a set of CSS custom properties. The defaults are sensible; the ones you usually want to change are primary, accent, and mode.
Every token is a plain CSS variable. Override any of them on any ancestor element:
.billing-section { --monigo-color-primary: #6366f1; --monigo-color-accent: #f43f5e; --monigo-radius-md: 12px; --monigo-font-sans: 'Inter', sans-serif;}/* Dark mode — Monigo toggles this automatically, but you can force it: */.billing-section[data-monigo-theme='dark'] { --monigo-color-bg: #0b1220; --monigo-color-fg: #f1f5f9;}
Want the full list? It’s in @monigo/tokens/monigo.css — or use the typed TOKEN_NAMES array:
The <MonigoPortal /> component bundles a lightweight internal router so the 5-minute demo stays a one-liner. For production apps that already have a router (Next.js App Router, Nuxt, SvelteKit, Remix, TanStack Router), import the page components and wire them into your own routes.
Clicking PayInvoiceButton calls POST /portal/invoices/:id/pay, which returns a gateway authorization_url. The component redirects the browser to that URL automatically.
<AddPaymentMethodButton @add="() => analytics.track('pm_setup_started')" @unsupported="() => alert('Card setup is not available for your region yet.')"/>
The add flow redirects to the payment gateway’s tokenization page (Paystack today). If your Monigo organisation uses a gateway that doesn’t yet support stored-card setup, the component emits unsupported and shows a localized message.
Every component renders three states out of the box: loading (skeleton), empty (“you have no invoices yet”), and error (with a Try again button). You can override any of them.
All web packages are SSR-safe. The components don’t touch window, document, or localStorage at module scope — only inside framework lifecycle hooks.
Framework
Tested setup
Next.js 14+
App Router. Mark pages that use <MonigoProvider> as client components ('use client'). The provider and every interactive component run client-side; static content is SSR-safe.
Nuxt 3
SSR just works. Don’t call useMonigoContext() inside <script setup> at the module level — use it inside a computed or onMounted.
SvelteKit
SSR + hydration both work. <MonigoProvider> renders its theme <style> tag server-side so there’s no flash of unstyled content.
Remix
Works. Render <MonigoProvider> in a route segment; it hydrates on the client.
The portal fetches data on the client regardless — portal tokens are customer-scoped and we don’t want them pre-fetched on a shared cache. The initial HTML shows skeletons; the data streams in after hydration.
v1 ships English. All user-visible strings live in a typed catalog you can override:
React
<MonigoProvider portalToken={token} locale="en-US" messages={{ 'invoices.title': 'Bills', 'invoices.action.pay': 'Pay this bill', 'subscriptions.cancel.confirm': 'Are you sure? This ends access at the end of the period.', }}> <MonigoPortal /></MonigoProvider>
Every key comes with a sensible default. The full list is exported as the MessageKey union from @monigo/portal-core.
By default, every component calls https://api.monigo.co/api/v1/portal/* directly from the browser with the X-Portal-Token header. If your security policy requires all traffic to flow through your own backend, pass a custom baseUrl and fetch:
Then set up a lightweight reverse proxy on your server that forwards /api/monigo/* to https://api.monigo.co/api/v1/* and injects the X-Portal-Token header (or validates one from a cookie you control).
Tree-shaking works end-to-end. A minimal integration (provider + InvoiceList only) ships well under 20 kB min+gzip in React, Vue, and Svelte. The full <MonigoPortal /> is under 60 kB min+gzip per framework.Flutter’s monigo_portal adds roughly 450 kB to release APKs (mostly from generated models). It uses dart:http — no extra native plugins — so it compiles unchanged for iOS, Android, web, macOS, Linux, and Windows.