@alexvornsand/design-system
v1.9.3
Published
This package is a **deterministic, opinionated design system** built on top of Mantine. It exists to eliminate design and implementation ambiguity, not to offer flexibility at the point of use.
Readme
Design System
This package is a deterministic, opinionated design system built on top of Mantine. It exists to eliminate design and implementation ambiguity, not to offer flexibility at the point of use.
If you are choosing how something looks while using this system, the system has already failed upstream.
Getting Started (single path)
Use createDesignSystem to register themes, then wrap your app with DesignSystemProvider.
import { createDesignSystem, defineThemeAliases, DesignSystemProvider } from "@alexvornsand/design-system";
const config = createDesignSystem({
themes: [
{
id: "neutral",
theme: defineThemeAliases({
colors: {
background: "#0f172a",
surface: "#111827",
border: "#1f2937",
text: "#e2e8f0",
mutedText: "#94a3b8",
primary: "#4f46e5",
secondary: "#7c3aed",
danger: "#ef4444",
},
radius: { sm: "4px", md: "8px", lg: "12px" },
shadow: {
sm: "none",
md: "0 4px 10px rgba(0,0,0,0.18)",
lg: "0 10px 24px rgba(0,0,0,0.28)",
},
typography: {
headingFontFamily: '"Inter", system-ui, sans-serif',
bodyFontFamily: '"Inter", system-ui, sans-serif',
},
}),
},
],
defaultThemeId: "neutral",
});
export function App() {
return (
<DesignSystemProvider config={config}>
{/* your app */}
</DesignSystemProvider>
);
}- To switch themes, pass
activeThemeIdtoDesignSystemProvider; ids must match registered themes and are validated in development. - To scope a different theme to a subtree (e.g., header) without nesting another provider root, wrap that subtree in
ThemeScope themeId="...". - Use a single app-owned
AppShellat the app entrypoint to wrap routes; setshellWidth("matchContent"default) once, and let pages opt into full width withPage contentWidth="full"(guide:../../docs/using/guides/app-shell-layout.md). - Policy remains internal/advanced; theme-only usage is the supported consumer flow today.
- See
../../docs/using/getting-started/index.mdfor the full consumer walkthrough, including multi-theme examples (guides/multiple-themes.md).
Purpose
This design system exists to:
- Provide a single, correct way to solve common UI problems
- Encode design intent structurally rather than stylistically
- Allow multiple unrelated products to share a coherent design language
- Minimize discretionary decisions in application code
The system is intended to be used whole. Partial adoption undermines its guarantees.
Non-Goals
This design system is not:
- A theme or theming framework
- A flexible component library
- A place to experiment with visual styles
- A thin wrapper around Mantine
- A toolkit that exposes visual configuration at the point of use
Mantine is an internal implementation detail. Application code must never import Mantine directly.
Core Doctrine
Determinism Over Choice
Every common UI problem has exactly one sanctioned solution.
Variation is achieved only through explicit, high-level levers defined at system or project boundaries, never through local props.
Meaning Drives Appearance
Visual differences are a consequence of:
- semantic intent
- structural placement
- contextual constraints
They are not the result of arbitrary variants, sizes, or colors.
Structure First
Layout and hierarchy are resolved structurally.
Spacing, prominence, and emphasis are derived from:
- regions
- archetypes
- composition rules
Components do not manage layout.
Explicit Boundaries
All semantic boundaries are explicit in code.
- Archetypes change only at Region boundaries
- Pages may contain multiple Regions (stacked or side‑by‑side)
- Archetype differences must never be expressed via per‑component styling or “modes”
- Destructive actions exist only at commitment points
- Escape hatches are rare and intentional
Accessibility Is Architectural
Accessibility is not layered on later.
Keyboard navigation, focus management, reduced motion, and contrast are guaranteed by the system itself.
Accessibility behavior is owned by:
- layout primitives
- controls
- patterns
Pages and applications must never patch accessibility behavior locally. If accessibility requires ad hoc fixes, the system is wrong.
System Model
Regions and Archetypes
All UI is divided into Regions. Each Region declares exactly one archetype:
- Instrument
- Workspace
- Reader
- Index
Archetypes define allowable ranges for:
- density
- contrast
- expressiveness
Components may not override these constraints.
Layout Primitives
All layout is constructed from a small, closed set of primitives:
- Page
- Region
- Section
- Stack
- Inline
- Cluster
- Grid
- Pane
- Frame
Ad hoc layout and spacing are forbidden.
Controls and Intent
Interactive controls expose semantic intent, not visual variants.
Universal intents:
- primary
- secondary
- tertiary
- neutral
- destructive
Visual treatment is derived from:
- intent
- structural role
- region context
destructive intent is reserved only for actions that immediately and irreversibly change state.
Controls that merely initiate a destructive flow (for example, opening a confirmation modal) must not be marked destructive. The destructive control appears only at the point of commitment, inside a guard pattern.
Patterns
Patterns own complexity, edge cases, and risk.
Examples include:
- menus
- modals
- confirmation flows
- empty states
Destructive actions exist only inside guard patterns.
Patterns, not pages, own:
- focus trapping
- keyboard flow
- screen‑reader announcements
- recovery behavior
Forbidden Practices
The following are explicitly forbidden in application code:
- Importing Mantine components directly
- Passing visual props (variant, size, color, etc.)
- Ad hoc spacing or margins
- Styling via className (except EscapeHatch)
- Creating new interaction patterns casually
- Patching accessibility behavior at the page level
Violations indicate either misuse or missing system capability.
Escape Hatches
Exactly one escape hatch mechanism exists.
Escape hatches:
- require explicit justification
- are easy to audit
- are expected to be temporary
They signal places where the system may need to evolve.
Evolution and Versioning
The system is allowed to evolve deliberately.
All changes are:
- explicit
- versioned
- documented
Breaking changes are justified in terms of doctrine, not aesthetics.
The Invariant
If two competent designers, given the same content and this system, produce meaningfully different UI, the system has failed.
This README is the source of truth for system usage and evolution. All tooling, documentation, and implementation defer to it.
