Skip to content

Latest commit

 

History

293 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

monoline-ui logo

monoline-ui

Monochrome React components for developer portfolios, documentation, and editorial interfaces.
Built with typed subpath exports and Tailwind CSS v4 design tokens.

npm JSR

CI Status Scorecard Status OpenSSF Scorecard License

Buy me a coffee at ko-fi.com

FeaturesQuick StartArchitectureSetupContributing


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.


Why Monoline UI

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.


Features

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.

Quick Start

pnpm add @chitrank2050/monoline-ui
import { 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>
	)
}

Documentation & Links

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

Tech Stack

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

Technical Specification

  • Module format: ESM-only ("type": "module")
  • Target: ES2022 / Bundler module resolution
  • Peer dependencies: react ^18.2 || ^19, react-dom ^18.2 || ^19, optional tailwindcss >=4
  • Runtime dependencies:
    • Radix UI primitives - dialog, popover, menu, tooltip, and form-control behavior
    • @radix-ui/react-slot - polymorphic render delegation
    • clsx + tailwind-merge - class composition
    • cmdk - 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.

Architecture

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
Loading

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.


Setup & Integration

1. Tailwind CSS v4

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.


2. Server and client runtime boundaries

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>
	)
}

3. React 19 Server Actions

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 } })
}

4. Link Polymorphism

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>

Development Commands

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            # Prettier

Release Process

Monoline uses Changesets for library version intent and keeps a two-phase release pipeline:

  1. Prepare - contributors add a changeset for library changes. Run Release 1 - Prepare PR on main to consume pending changesets and open a release PR.
  2. Finalize - merge the release PR. Release 2 - Finalize Tag verifies 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.


Contributing

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.


Community & Support

  • 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. ✨

Security & Quality

  • 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

About

A token-first, responsive React component library and Tailwind CSS v4 design system built from my portfolio's visual language.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages