Monochrome React components for developer portfolios, documentation, and editorial interfaces.
Built with typed subpath exports and Tailwind CSS v4 design tokens.
Features • Quick Start • Architecture • Setup • Contributing
Monoline UI is a monochrome component library for developer sites, editorial interfaces, and documentation playgrounds. Its small token set keeps the emphasis on type, spacing, and layout, and can be adapted without maintaining separate light and dark utility classes.
Tip
Monoline UI focuses on the parts of developer portfolios and documentation sites that tend to be rebuilt from scratch: editorial layout, navigation, code examples, project summaries, and supporting metadata. The package exposes typed components through explicit server and client entrypoints.
| Feature | Description |
|---|---|
| ⚫ Monochrome-first | A compact grayscale token set shared by light and dark themes. |
| 🚀 Server-safe static primitives | Presentational entrypoints can render without a Monoline client boundary. |
| ⚡ Explicit client components | Interactive entrypoints declare client runtime behavior in their source/docs. |
| 🔗 Link polymorphism | Configure routing globally, per link, or through asChild. |
| 🌲 Direct ESM subpaths | Import components through explicit package entries. |
| 🎛️ Token-driven | Customize spacing, scale, and type via CSS custom properties. |
| 📦 47 components | Each component has a live preview, typed API, and implementation notes. |
| 🌊 Tailwind CSS v4 | @source scanning includes utilities used by installed components. |
pnpm add @chitrank2050/monoline-uiimport { Footer } from "@chitrank2050/monoline-ui/footer"
import "@chitrank2050/monoline-ui/theme.css"
export default function Page() {
return (
<Footer size="md">
<Footer.Status>Available for contracts</Footer.Status>
<Footer.Subscribe action={subscribeAction} />
</Footer>
)
}| Resource | URL |
|---|---|
| Docs | monolineui.chitrankagnihotri.com |
| Components | 47 interactive React references |
| Foundations | Tailwind CSS v4 design tokens |
| Patterns | Component composition recipes |
| Accessibility | Behavior and consumer responsibilities |
| Theming | Light, dark, system, and token overrides |
| Compatibility | React, Next.js, Tailwind, and browser support |
| Installation | React and Tailwind CSS v4 setup |
| npm | npmjs.com/package/@chitrank2050/monoline-ui |
| JSR | jsr.io/@chitrank2050/monoline-ui |
| Repository | github.com/chitranklabs/monoline-ui |
| Case study | Architecture and project outcomes |
| Changelog | CHANGELOG.md |
| Layer | Technology | Version |
|---|---|---|
| Runtime | Node.js | >=24.14.0 |
| Package Manager | pnpm | 11.18.0 |
| Framework | Next.js (App Router) | ^16 |
| UI Runtime | React | ^19 |
| Compiler | TypeScript | ^6.0 |
| Styling | Tailwind CSS + PostCSS | ^4 |
| Bundler | tsup (ESM) | ^8 |
- Module format: ESM-only (
"type": "module") - Target: ES2022 / Bundler module resolution
- Peer dependencies:
react ^18.2 || ^19,react-dom ^18.2 || ^19, optionaltailwindcss >=4 - Runtime dependencies:
- Radix UI primitives - dialog, popover, menu, tooltip, and form-control behavior
@radix-ui/react-slot- polymorphic render delegationclsx+tailwind-merge- class compositioncmdk- command palette interaction model
- Performance invariant: Static component subpaths do not introduce a Monoline client boundary. The mixed root barrel is client-safe because it also exports interactive components; use documented component subpaths for RSC optimization.
graph TD
A[Consumer App] -->|import| B["@chitrank2050/monoline-ui"]
B --> C["Static primitives (server-safe)"]
B --> D["Interactive Subcomponents (Client)"]
C --> E["CSS Foundations / Token Layer"]
D --> E
F["Tailwind v4 @source scan"] --> B
The pnpm workspace separates the published UI package from its Next.js website.
The website consumes built package exports, just as an installed consumer does.
pnpm check:package also installs the real npm tarball in temporary React 18
and React 19 projects outside the workspace, including a Next.js/Tailwind build.
The workspace migration safeguards describe the package boundaries and the contracts that must remain unchanged.
monoline-ui/
├── apps/website/ ← Next.js playground & documentation
├── packages/ui/
│ ├── src/components/ ← 47 UI components (Avatar, Button, Footer…)
│ ├── src/foundations/ ← CSS layers, design tokens, breakpoints
│ └── package.json ← Published library identity and dependencies
├── scripts/
│ └── build-lib.mjs ← ESM bundling script
├── package.json ← Shared tooling and repository commands
└── pnpm-workspace.yaml
Important
Run pnpm dev or pnpm build from the repository root. Both build the UI
package before starting the website. After editing library code, run
pnpm build:lib again; website source edits retain Next.js fast refresh.
In your root stylesheet, point Tailwind's compiler at the compiled Monoline outputs so only used utilities ship:
@import "tailwindcss";
@import "@chitrank2050/monoline-ui/theme.css";The published theme registers Monoline's compiled component sources with Tailwind, so consumers do not need to maintain a package-specific @source path.
Important
Static primitives can render without a Monoline client boundary. Checkbox, CodeBlock, CommandSearch, Dialog, DropdownMenu, Label, Popover, Progress, RadioGroup, SegmentedControl, Select, Separator, ThemeSwitcher, Toc, Toggle, and Tooltip require client JavaScript. The final bundle also depends on your application and passed children.
Import static primitives from their component subpaths to preserve that boundary. The root package export intentionally remains client-safe because it mixes static and interactive exports.
import { Footer } from "@chitrank2050/monoline-ui/footer"
export default function MyFooter() {
return (
<Footer size="md">
<Footer.Status>Available for contracts</Footer.Status>
<Footer.Subscribe action={subscribeFormAction} />
</Footer>
)
}Pass a standard async Server Action to the action prop. No client JavaScript required:
// app/actions.ts
"use server"
export async function subscribeFormAction(formData: FormData) {
const email = formData.get("email")
await db.newsletter.create({ data: { email } })
}Monoline supports three levels of client-router control:
A. Global - pass your router's Link once to override all internal links:
import Link from "next/link"
export default function MyFooter() {
return <Footer linkComponent={Link} columns={myColumns} />
}B. Per-link - override individual links in the config array:
import Link from "next/link"
const columns = [
{
title: "Navigate",
links: [
{ label: "Blog", href: "/blog", as: Link },
{ label: "Twitter", href: "https://x.com", external: true },
],
},
]C. asChild - composable override using the Radix slot pattern:
import Link from "next/link"
;<Footer.Link asChild>
<Link href="/about">About</Link>
</Footer.Link>pnpm install # Install dependencies
pnpm dev # Launch Next.js dev server (HMR)
pnpm build # Build the Next.js playground
pnpm build:lib # Bundle the component library into /dist
pnpm build:all # Both builds in sequence
pnpm test # Run Vitest test suite
pnpm typecheck # TypeScript type check (no emit)
pnpm lint # ESLint + Markdownlint
pnpm format # PrettierMonoline uses Changesets for library version intent and keeps a two-phase release pipeline:
- Prepare - contributors add a changeset for library changes. Run
Release 1 - Prepare PRonmainto consume pending changesets and open a release PR. - Finalize - merge the release PR.
Release 2 - Finalize Tagverifies the prepared version, tags the verified commit, publishes to npm and JSR, then creates the GitHub release.
Future notes live in packages/ui/CHANGELOG.md; the root changelog remains a historical archive. Website-only work does not bump the library. See the release guide.
Contributions are welcome. Please read the Contributing Guide before opening a PR. All commits are validated by git-hygiene and must follow the Conventional Commits spec.
- Security: See SECURITY.md for reporting vulnerabilities.
- Conduct: We follow the Contributor Covenant.
- Support: If you use Monoline UI in your project, a star or credit is appreciated. ✨
- Secret Scanning: Gitleaks prevents credential leaks in every commit.
- Workflow Auditing: Zizmor ensures GitHub Actions follow security best practices.
- Supply Chain: All GitHub Actions are pinned to secure commit SHAs.
Developed with ❤️ by Chitrank Agnihotri