Installation
Niemeyer ships as a private GitHub Packages npm package built around Tailwind 4. Six numbered steps below take you from a fresh app to a working <Button>.
1. Configure GitHub Packages access
Create a GitHub personal access token (classic) with read:packages and export it as GITHUB_TOKEN. Then add this .npmrc at the project root (Yarn Classic reads it directly; Yarn Berry users can set the equivalent npmScopes in .yarnrc.yml):
# .npmrc — at project root
@morada-ai:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
2. Install the package and peers
Tailwind 4 and @tabler/icons-react are peer dependencies — install them in your app so a single copy is hoisted next to the package.
# Install the package
yarn add @morada-ai/niemeyer
# Plus the peer dependencies (one copy in your app)
yarn add tailwindcss@^4
yarn add @tabler/icons-react3. Configure PostCSS
Tailwind 4 ships its PostCSS plugin separately. Add it to your config (no autoprefixer needed):
// postcss.config.mjs
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};4. Wire the stylesheet
Three explicit @imports in app/globals.css, in this order. You only need one @source for your own app code — the package's theme.css already self-sources its components, and Tailwind 4 merges @source directives across all imported stylesheets.
/* app/globals.css */
@import "tailwindcss";
@import "@morada-ai/niemeyer/styles";
@import "tw-animate-css";
/* Only your app code — the package self-sources its own components */
@source "./app/**/*.{ts,tsx}";5. Load fonts
Niemeyer expects two CSS variables: --font-heading (Outfit) and --font-body (Lato). Easiest path is next/font:
// app/layout.tsx
import { Outfit, Lato } from "next/font/google";
const outfit = Outfit({
subsets: ["latin"],
variable: "--font-heading",
});
const lato = Lato({
subsets: ["latin"],
weight: ["300", "400", "700", "900"],
variable: "--font-body",
});
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html className={`${outfit.variable} ${lato.variable}`}>
<body>{children}</body>
</html>
);
}6. Re-export `cn()` so consumer code can import it locally
The package ships the same cn pattern as shadcn (clsx + tailwind-merge). Both helpers are bundled, so a one-line re-export is enough:
// src/lib/utils.ts
export { cn } from "@morada-ai/niemeyer/utils";Optional: enable the ESLint plugin
Catches design-system violations automatically (no hardcoded colors in className="…", no lucide-react imports, no native <button>/<input>):
// eslint.config.js
const niemeyer = require("@morada-ai/niemeyer/eslint");
module.exports = [niemeyer.configs.recommended];Themes
Two color schemes (gray default, black high-contrast), each with light and dark mode. Toggle by setting one of these classes on the root element:
| Root class | Resulting theme |
|---|---|
| (none) or .theme-gray | Gray — light (default) |
| .theme-gray.dark | Gray — dark |
| .theme-black | Black — light (high contrast) |
| .theme-black.dark | Black — dark |