Every product we build at piqadot uses the same underlying design system. We call it Mono UI. After years of maintaining it internally, we have released it publicly — and this tutorial is the fastest way to go from zero to a working component.
By the end of this guide you will have Mono UI installed, a button and input rendered in your project, and a custom theme applied. The guide assumes a React project with TypeScript; the concepts apply to any setup supported by the library.
Installing Mono UI
Install the core package and its peer dependencies:
npm install @piqadot/mono-ui
Mono UI requires React 18 or higher. Wrap your application root with the MonoProvider to make the default theme available:
import { MonoProvider } from '@piqadot/mono-ui';
export default function App({ children }: { children: React.ReactNode }) {
return <MonoProvider>{children}</MonoProvider>;
}
That is the full setup for the default theme. You can start using components immediately.
Your first components
Mono UI components are imported individually to support tree-shaking. Import what you need:
import { Button, Input, Stack } from '@piqadot/mono-ui';
function ContactForm() {
return (
<Stack gap="md">
<Input label="Email address" type="email" placeholder="you@example.com" />
<Button variant="primary" type="submit">
Subscribe
</Button>
</Stack>
);
}
Stack is a layout primitive that arranges its children vertically with consistent spacing. Input includes a visible label and accessible markup out of the box — the label prop renders a <label> element with a for attribute pointing to the input. Button with variant="primary" uses the theme's accent color.
All interactive components in Mono UI are keyboard accessible and meet WCAG 2.1 AA contrast requirements at the default theme settings. You do not need to add ARIA attributes for basic usage.
Customizing the theme
The default theme works, but most projects have brand colors and type choices. Pass a theme object to MonoProvider:
import { MonoProvider, createTheme } from '@piqadot/mono-ui';
const theme = createTheme({
colors: {
accent: '#5c6bc0',
accentHover: '#3f51b5',
surface: '#ffffff',
surfaceAlt: '#f5f5f5',
text: '#1a1a1a',
textMuted: '#666666',
},
typography: {
fontFamily: '"Inter", system-ui, sans-serif',
scaleBase: 16,
},
radius: {
sm: 4,
md: 8,
lg: 16,
},
});
export default function App({ children }: { children: React.ReactNode }) {
return <MonoProvider theme={theme}>{children}</MonoProvider>;
}
createTheme validates the token structure at runtime in development — if a required token is missing it logs a warning with the path. In production the warning is silenced and the default value is used, so a missing token never breaks the UI.
Scaling with your project
As your project grows, two patterns help maintain consistency.
First, co-locate component variants by creating thin wrappers that fix options appropriate to your brand rather than passing them everywhere:
import { Button } from '@piqadot/mono-ui';
export function PrimaryButton(props: React.ComponentProps<typeof Button>) {
return <Button {...props} variant="primary" size="md" />;
}
Second, use the theme token system for any custom CSS rather than hardcoding values. Mono UI exposes its resolved tokens as CSS custom properties on :root, so your own stylesheets can reference var(--mono-color-accent) rather than repeating the hex value. This keeps custom components in sync when the theme changes.
The full component catalog and API reference are at piqadot.com/designs/mono-ui. The design system is open source under the MIT license.