A minimal, monotone, unopinionated design system. Tokens and React components for teams that want their product to look like their product, not like the design system.
Live docs: monoset.design
Scaffold a new project: npm create monoset-app@latest
Most design systems arrive with a visual personality already baked in. Rounded corners everywhere, pastel accents, an illustration style. The other common shape is a sprawl of six hundred tokens across a dozen brand themes that nobody fully configures.
Monoset is a third path. The whole palette is one 12-step neutral ramp. Every surface, every border, every piece of text reads from that scale, so the system has one dial (tone) instead of twelve. The shapes are conservative: 4px grid, hairline borders, shadows reserved for surfaces that are actually floating. Motion has three durations and one easing curve, and it always gets out of the way once it's told you what happened.
Underneath, the interactive components wrap Radix primitives. You don't have to reinvent focus management to ship a menu, and you don't have to dig through ARIA specs to ship an accordion.
If you want a system that stays quiet so your product can be the loud thing, that's the pitch.
This repo is a monorepo with three workspace packages and a showcase site.
| Package | What it is |
|---|---|
@monoset/tokens |
CSS custom properties and JSON tokens. Drop-in for any framework. |
@monoset/motion |
Framer Motion presets: easings, durations, reusable variants. |
@monoset/react |
React component library. Around 25 components. Styles ship as one CSS file. |
website/ |
Vite + React docs site. What you see at the live URL. |
If you don't need React, pull in the CSS variables and style your own components against them.
npm install @monoset/tokens@import "@monoset/tokens/css";
.card {
background: var(--bg);
color: var(--fg1);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-md);
padding: var(--space-4);
font-family: var(--font-sans);
}npm install @monoset/react @monoset/tokens react react-dom framer-motionimport "@monoset/tokens/css";
import "@monoset/react/styles.css";
import { MonosetProvider, Button, Field, Input } from "@monoset/react";
export default function App() {
return (
<MonosetProvider>
<Field label="Email" help="We'll send a confirmation.">
{({ id }) => <Input id={id} type="email" placeholder="you@example.com" />}
</Field>
<Button variant="primary">Continue</Button>
</MonosetProvider>
);
}|
Button Four variants, three sizes.
|
Input & Field Label + helper + error, wired up.
|
|
Badge Status, counts, category tags.
|
Card Outline, elevated, inset.
|
|
Checkbox & Switch Same look, different semantics.
|
Tabs Underline and segmented.
|
|
Alert & Toast Inline and transient feedback.
|
Avatar Initials, sizes, stacking. |
|
Accordion Disclosure panels, Radix-backed.
|
Slider A range input with a readout.
|
|
Toggle group A segmented control.
|
Kbd Keyboard-shortcut chips.
|
|
Spinner Waits longer than 400ms.
|
Table Dense rows, hairline separators.
|
Plus: Textarea, RadioGroup, Select, Toggle, Dialog, Popover, Tooltip, DropdownMenu, Breadcrumb, Pagination, EmptyState, Skeleton, Separator, Progress.
Styles ship in one @monoset/react/styles.css. No CSS-in-JS runtime. The only provider you need is <MonosetProvider>, which sets up the toast queue and the shared tooltip root.
Monotone. If a component feels like it needs color, something else is off. Lean on tone and weight first, and reach for iconography before you reach for a hue.
Hairlines beat shadows. A 1px border carries almost the whole system. Shadows are reserved for surfaces that are actually floating above something, like a modal scrim or a popover.
4px grid. Everything snaps. The temptation to sneak in a 7px margin because it "looks right" is where systems start to decay.
Motion confirms, then gets out of the way. Three durations (120/180/280ms), one easing curve. Nothing springs, nothing bounces, nothing hangs around for 900ms pretending to be cinematic.
Don't reinvent. If a native web control works, use the native one. If accessibility gets interesting (menus, dialogs, sliders), reach for Radix and put a monotone coat of paint on top.
git clone https://github.com/antonijap/monoset-design-system
cd monoset-design-system
npm install
# Run the docs site (Vite)
npm run dev
# Build the library packages
npm run build --workspace=@monoset/motion
npm run build --workspace=@monoset/reactRequires Node 20+. Uses npm workspaces, so the single npm install at the root wires everything up.
Issues and PRs are welcome. A few things worth knowing before you open one:
Don't add color. Suggestions that introduce brand hues, accent colors, or traffic-light status colors will be closed. The monotone constraint is load-bearing.
Don't add a component you won't use. The bar is "I needed this, couldn't find it, would reuse it on three other projects", not "most libraries have one". A smaller kit that teams actually reach for beats a big kit where half the components rot.
Match what's there. One file per component, classes prefixed .ms-, TypeScript types exported from the package root. If you're adding styles, keep the same CSS-file structure used elsewhere in @monoset/react/src/styles.css.
For anything bigger than a tweak, open an issue first.
MIT © Antonija Pek
Built on top of Radix UI primitives and Framer Motion. Influenced by Radix Colors (the restraint), shadcn/ui (the ship-styles-as-CSS approach), and every design system that tried to do less and ended up lasting longer.













