@mtdt/nextgen-design-system
v2.3.0
Published
The NextGen design system: accessible React components for building SaaS platforms, designed to be readable by machines as well as people.
Maintainers
Readme
NextGen Design System
A React component library owned by the design team, built so that AI-generated UI comes out on-system by default.
Most design systems are written for people to read. This one is written for a machine to consume first: every component's variants are extracted to a machine-readable catalogue, every design decision is a named token, and the rules are explicit enough that a model can follow them without guessing.
What's in here
| | | | --------------------- | -------------------------------------------------------------------- | | 46 components | Button, Input, Select, Dialog, Toast, Tabs, Table, Sidebar, and more | | 1209 icons | Cut from Lucide's own source, no runtime dependency | | 113 colour tokens | 88 primitives, 25 semantic pairs — light and dark | | 522 stories | Every variant of every component, in both themes |
Features
- Accessible — every overlay and form control is built on Radix UI
primitives (16 components: Dialog, Select, Popover, Tooltip, Tabs, Switch, Checkbox, Radio and
more), so keyboard navigation, focus management and screen-reader semantics come from a primitive
that already got them right. Storybook runs
addon-a11yon every story, and the end-to-end suite runs axe. The target is WCAG 2.1 AA. - Themeable — every colour, radius and shadow is a CSS variable, not a hardcoded value. Light and
dark both ship in
globals.css, and a product can override any token without forking a component. - Type-safe — TypeScript
strict, and then five settings beyond it:noUncheckedIndexedAccess,exactOptionalPropertyTypes,noUnusedLocals,noUnusedParametersandnoFallthroughCasesInSwitch. Zeroanyin the codebase. - Tree-shakeable —
sideEffectsis declared and the build emits per-component chunks, so importingButtondoesn't drag inTable. - Tested — 1382 unit tests across 46 components, run on every push alongside lint, typecheck and both builds.
- Documented — 522 stories, every variant of every component, in both themes, with live prop controls.
- Machine-readable —
component-catalog.jsonextracts every component and every variant straight from the CVA definitions, so a model can be told what exists instead of guessing at it. This is the part that makes "AI-ready" a claim rather than a slogan.
Using it in a product
npm install @mtdt/nextgen-design-systemimport '@mtdt/nextgen-design-system/styles.css';
import { Button, Callout, Dialog, DialogContent, DialogTitle } from '@mtdt/nextgen-design-system';The stylesheet is not optional and is not automatic. Every component here is Tailwind utility
classes with an mdt- prefix; without that one import you get correct, accessible, completely
unstyled markup — and no error to tell you why. Import it once, at the root of your app.
You do not need Tailwind to use this. The stylesheet ships compiled, so the package works in any
React app. If you do use Tailwind, the mdt- prefix means our classes cannot collide with yours —
that is what the prefix is for.
React 18 or 19, as a peer dependency. Both ESM and CommonJS, with types for each.
If an agent is doing the work
The package ships AGENTS.md — the rules an AI coding agent has to follow inside a project
that consumes this system. Point your agent at it once and the constraints travel with the version:
Follow the rules in node_modules/@mtdt/nextgen-design-system/AGENTS.mdPut that line in the consuming project's CLAUDE.md (or .cursorrules, or whatever your agent
reads). Bump the package and the rules update — nobody's copy goes stale, and five projects cannot
end up with five interpretations of the guidance.
MIGRATION-PROMPT.md ships too — one prompt to paste into a fresh Claude Code session opened
in a project being migrated. It installs the package, writes the rules into that project's own
CLAUDE.md, surveys what is there before touching anything, and migrates one flow at a time with a
verification pass after each. Written for somebody who has never chosen a component and will not be
reviewing the choice.
The catalogue ships too, so the agent can check what exists rather than guess:
CAPABILITIES.md to read, capability-catalog.json to filter. Without those, "use the design
system's component" is an instruction with nothing to check against.
Versioning — a changeset per user-facing pull request
If your change reaches the published package, add one:
npm run changesetIt asks for a bump — patch, minor or major — and a sentence for somebody reading the changelog
rather than the diff. Commit the file it writes into .changeset/ and push. CI enforces this: a
pull request that touches src/ (excluding tests, stories, docs and dev.tsx) or
tailwind.config.ts or vite.config.ts and carries no changeset fails.
Everything else is exempt, on purpose. A README fix, a story, a workflow, a plan document — none of them change a byte of the tarball, and demanding a version bump for them teaches people the gate is noise. A gate people learn to route around is worse than no gate.
If a change genuinely ships nothing, label the pull request no changeset. It is a label rather
than a silent pass so the decision leaves a trace.
At release time npm run version consumes every waiting changeset, works out the bump, writes
CHANGELOG.md, and updates package.json. Commit that, then publish.
Releasing
No npm token exists, deliberately. Publishing runs from Actions → Release, and the workflow proves its identity to npm through GitHub's OIDC — npm's Trusted Publishing. There is no secret to leak, rotate, or forget to renew, and nobody who can open a pull request can reach a credential, because there is not one.
It needs the package on npmjs.com to name this repository and this workflow file under
Settings → Trusted Publisher. Renaming .github/workflows/release.yml breaks publishing until
that is updated too — the trade for having no credential.
Leave publish unticked the first time. The run does the whole gate, builds, verifies the package,
and attaches the tarball as an artifact you can download and install in a scratch app. Tick it when
you want the real thing; npm cannot take a version back.
Checking a build before it goes out
npm run build # includes the stylesheet and the CommonJS types
npm run verify:package # everything `exports` promises actually exists
npm pack # the tarball, to install in a scratch app and tryThat last step is worth doing rather than trusting. This package spent months naming
dist/styles.css in its exports map without ever building the file: npm pack succeeded,
npm install succeeded, and every component rendered unstyled. A green build and a working artifact
are two different claims.
Looking at it
You don't need to install anything. The Storybook is published on every change:
https://niravbhatt1317.github.io/nextgen-design-system/
Use the sidebar to browse components, the Controls tab to change props live, and the theme toggle in the toolbar to flip the whole page between light and dark.
Running it yourself
You need Node.js 20+ and npm.
git clone https://github.com/niravbhatt1317/nextgen-design-system.git
cd nextgen-design-system
npm install
npm run storybookStorybook opens at http://localhost:6006.
Always
git clone— never copy the folder. Copying carriesnode_modulesacross, and anode_modulesbuilt on one operating system does not work on another. If you copied the folder and nothing runs, deletenode_modulesand runnpm installagain.
New here?
Start with docs/ONBOARDING.md — nothing to nothing-to-first-merged-change.
If you use Claude Code, the whole setup is one command. Clone, open the folder, start a session and type:
/onboardIt installs what's missing, verifies the project runs, reads the entire rulebook, and briefs you on what this system is and what's missing from it — then waits for you to pick something to build.
After that, docs/DESIGNER-GUIDE.md is the day-to-day working guide.
The rules that matter
Four rules carry most of the weight. Breaking any of them is how this system drifts.
🔒 Components always use tokens
If the token you need doesn't exist, stop and say so — don't hardcode a value, approximate with a nearby token, or reach for a raw hex. A missing token is a design decision for the owner to make.
- Every token that exists →
TOKENS.md - Every category that doesn't exist yet →
MISSING-TOKENS.md - Where the rule is currently broken →
TOKEN-REPORT.md
Do not add colours. The palette is 88 primitives and 25 semantic pairs, and it stays that size unless the design owner decides otherwise. A second green makes "which green" a live question on every component after it.
🎨 Lucide is the only icon source
One icon means one thing — never use the same glyph for two features. Every icon goes through
<Icon name="..." />; never hand-draw an inline <svg>. The artwork is copied in rather than
imported, so products using this library gain no icon dependency and no icon changes shape without
a commit.
⚠️ Class order matters
cn() merges classes with the mdt- prefix registered, which means the last class wins.
// ❌ `px-3` sets both sides, overwriting the `pr-9` written before it
cn(closable && 'mdt-pr-9', 'mdt-px-3 mdt-py-1.5');
// ✅ the narrower rule goes last
cn('mdt-px-3 mdt-py-1.5', closable && 'mdt-pr-9');👀 Verify in a browser, not just in tests
Unit tests pass while the pixels are wrong. Badge text once measured 2.0:1 contrast — unreadable, every test green. After any visual change, render the story in a real browser in both themes and look at it.
Full detail on all four lives in CLAUDE.md.
Conventions
CSS classes all carry the mdt- prefix:
className = 'mdt-flex mdt-items-center mdt-bg-primary'; // ✅
className = 'flex items-center bg-primary'; // ❌Colours are always semantic, never hardcoded:
'mdt-bg-primary mdt-text-primary-foreground'; // ✅
'mdt-bg-blue-500 mdt-text-white'; // ❌Every component is a folder of five files:
src/components/Button/
├── Button.tsx # the component
├── Button.types.ts # its types
├── Button.test.tsx # its tests
├── Button.stories.tsx # its Storybook page
└── index.ts # its exportsCommands
| Command | What it does |
| ------------------------- | ----------------------------------------------------------------- |
| npm run storybook | Browse components at localhost:6006 — the one you'll use most |
| npm test | Run every test |
| npm run lint | Check code style |
| npm run typecheck | Check types |
| npm run check:tokens | Report hardcoded values that should be tokens |
| npm run build | Build the library |
| npm run build-storybook | Build the static Storybook site |
| npm run generate-icons | Re-cut every icon from Lucide's source |
How changes reach the live site
Every push to main runs CI — lint, typecheck, tests, token check,
and both builds — then redeploys Storybook to GitHub Pages.
A change is live a few minutes after it merges.
Origin
This library began life on Azure DevOps
(dev.azure.com/Motadata/NextGen/_git/motadata-react-library), developer-owned. It now lives here,
and ships as @mtdt/nextgen-design-system,
owned by design, with CI rebuilt to match. Nothing here has been merged back.
License
MIT — see LICENSE.
