01 · Install
Add the package
@flatpay-dk/ui and @flatpay-dk/tailwind-preset ship as private packages on GitHub Packages under the FLATPAY-DK org. That means two pieces of one-time setup before pnpm add resolves: a registry pointer in the project’s .npmrc and a token in your home folder. Once both are in place, every Flatpay project on this machine installs without further ceremony.
First-time setup (once, ever)
1. Get a token. At github.com/settings/tokens/new generate a classic personal access token with the single scope read:packages. After it’s generated, click Configure SSO and authorize FLATPAY-DK. Classic tokens at FLATPAY-DK don’t need admin approval — the whole thing takes ~2 minutes.
2. Save it to your home folder. In a terminal:
npm login --scope=@flatpay-dk --registry=https://npm.pkg.github.comUsername: your GitHub login. Password: the token. Email: whatever. The token is written to ~/.npmrc — never to a project file, never to a repo. Every future Flatpay project just works.
With auth in place, each project also needs a one-line registry pointer so pnpm knows where to look for the @flatpay-dk scope. Drop this at the project root:
.npmrc
@flatpay-dk:registry=https://npm.pkg.github.comThen install:
bash
pnpm add @flatpay-dk/ui @flatpay-dk/tailwind-presetPrerequisites
The package targets react@^18 || ^19, react-dom@^18 || ^19, and either next@^15 or next@^16 (Next is an optional peer — only needed if you use useFlatpayFonts). Tailwind v4 + an @import "tailwindcss" entry in your CSS is the canonical setup. Vite / CRA / Remix consumers running React 18 + Tailwind v3 are also supported via the dedicated entries in Other stacks.
02 · Wire styles & fonts
Two imports and a className
The preset imports the canonical token CSS, maps the system’s semantic vars onto the Tailwind @theme namespace, and ships the .eyebrow utility. Add it after Tailwind. The @source line below points Tailwind v4 at the compiled component bundle in node_modules/@flatpay-dk/ui/dist/ so utilities used inside the package show up in your build. Adjust the relative path if your global stylesheet lives somewhere other than app/globals.css.
app/globals.css
@import "tailwindcss";
@import "@flatpay-dk/tailwind-preset";
@source "../node_modules/@flatpay-dk/ui/dist/**/*.js";Then mount the brand fonts on <html>. useFlatpayFonts() wraps Inter Tight and Martian Mono in next/font/local and returns a className that wires --font-sans and --font-mono in one line.
app/layout.tsx
import { useFlatpayFonts } from "@flatpay-dk/ui/fonts";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const { className } = useFlatpayFonts();
return (
<html lang="en" className={className}>
<body>{children}</body>
</html>
);
}Founders Grotesk is licensed; not in the package
The canonical Flatpay display face — Founders Grotesk X Condensed by Klim Type Foundry — is commercial and is notincluded in the published tarball. Headings fall back to Inter Tight via the preset’s --font-display: var(--font-display, var(--font-sans)) fallback. Internal Flatpay surfaces with a Klim license wire Founders locally on top of useFlatpayFonts — see apps/portal/app/fonts.ts in the Flatpay monorepo for the reference shape.
03 · Render a component
Import, render, done
Components are tree-shakeable named imports. There’s no provider, no theme wrapper — every component reads from token CSS variables, so dark mode is one [data-theme="dark"] attribute on <html>.
tsx
import { Button } from "@flatpay-dk/ui";
export function CaptureAction() {
return <Button>Capture payment</Button>;
}Browse the full set under Components. Every page lists props, variants, and the component’s place in the system.
04 · Reach for a token
Tokens are CSS variables
Every color, surface, and stroke is a CSS custom property. The preset re-exposes them as Tailwind utilities for backgrounds and borders; for text colors and one-off styles, reach for the variable directly. Both idioms produce the same swatch and re-theme automatically under [data-theme="dark"].
<span className="bg-accent-yellow-subtlest" />background: var(--background-accent-yellow-subtlest);The full token reference — every color step, every surface, the layering rule — lives at Foundations · Tokens.
05 · Other stacks
Vite, React 18, Tailwind v3
The package ships compiled JavaScript and reads the same token CSS variables on every stack — nothing about the components is Next-specific. Consumers on Vite + React 18 + Tailwind v3 (Lovable, CRA, Remix, plain Vite) wire two different entries: a CommonJS Tailwind v3 preset at @flatpay-dk/ui/tailwind-v3 and a CSS-only @font-face entry at @flatpay-dk/ui/fonts/css. The component bundle, the token CSS at /styles, and dark-mode behavior are identical to the Next path.
Skip @flatpay-dk/tailwind-preset — it’s Tailwind v4 only. The v3 preset below is its equivalent and reads the exact same CSS variables, so swatches don’t drift between stacks.
bash
pnpm add @flatpay-dk/uitailwind.config.ts
import flatpay from "@flatpay-dk/ui/tailwind-v3";
export default {
presets: [flatpay],
content: [
"./src/**/*.{ts,tsx}",
"./node_modules/@flatpay-dk/ui/dist/**/*.js",
],
};src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "@flatpay-dk/ui/styles"; /* token CSS variables */
@import "@flatpay-dk/ui/fonts/css"; /* @font-face + --font-* */That’s the whole setup. No provider, no className on <html> — the CSS entry sets --font-sans and --font-mono on :root globally. Toggle dark mode with [data-theme="dark"] on <html> the same way the Next path does.
Display face fallback
Founders Grotesk X Condensed isn’t in the published tarball (Klim license). On every stack, headings using font-display fall back to Inter Tight via --font-display: var(--font-display, var(--font-sans)). Layer your own @font-face for Founders after the imports above if you hold the license.
What’s next
Beyond the install
- BrowseThe system at a glance — what the three sections do and the house rules every page runs on.
- FoundationsTokens, color, type, spacing — the smallest decisions every component inherits.
- ContributeExtend, promote, add a token, file debt — how prototypes turn into system primitives.