Core Design System
The Design System is not a Core engine and not a Core utility in the operational sense. It is Shared Product Infrastructure — a layer the platform team governs so every module team builds on the same visual and interaction foundation. It lives alongside Core, not inside it.
Why This Exists
Thirty-two modules. Multiple teams. Different tech stacks. Different build timelines.
Without a shared design system, each module builds its own buttons, its own forms, its own error states, its own Lisan ud Daawat text handling. By the time five modules are live, the platform looks like five different products. Operators need retraining per module. Mumineen lose confidence when moving between screens. Accessibility is inconsistently handled and nobody owns the gap.
The Design System solves this at the source. Build it once. Every module inherits it. The Mumin moving from registration to pass status to Mawaid booking experiences one platform — not three apps that happen to share an ITS login.
The Three-Layer Model
The Design System is delivered in three layers. Every module uses Layer 1. React modules use Layer 1 and Layer 2. Non-React modules use Layer 1 and follow Layer 3.
Layer 3 — Patterns & Guidelines (documentation, Storybook, design review gate)
Layer 2 — Component Library (React package: @miqaat-core/design-system)
Layer 1 — Design Tokens (CSS custom properties + rem scale — all stacks)
Layer 1 — Design Tokens
Design tokens are the single source of truth for every visual decision: colors, typography, spacing, border radius, shadow, z-index, motion. Every module imports the token file. No module hardcodes a color hex or a pixel value.
rem-Based Scale — Responsive by Default
All spacing and typography tokens are defined in rem, not px. This is the foundation of responsive and accessible design.
Why rem matters:
rem is relative to the root font size (<html> element). The browser default is 16px. When a user has set their browser font size to 20px for readability, every rem value on the platform scales up proportionally — without any module doing anything special. This is also the correct way to respect WCAG 1.4.4 (Resize text) — content must remain readable when text is scaled up to 200%.
Pixel-based designs break this. A button padded with padding: 12px stays at 12px regardless of the user's font preference. A button padded with padding: 0.75rem scales naturally.
Root font size and breakpoints:
:root {
font-size: 16px; /* base — desktop */
}
@media (max-width: 768px) {
:root {
font-size: 15px; /* tablet — slight scale down */
}
}
@media (max-width: 480px) {
:root {
font-size: 14px; /* mobile — scale down */
}
}
By changing only the root font size, the entire platform scales. No module needs per-breakpoint overrides for most elements — the token system handles it.
Spacing tokens:
:root {
--space-1: 0.25rem; /* 4px base */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
}
Typography scale:
:root {
--text-xs: 0.75rem; /* 12px — captions, labels */
--text-sm: 0.875rem; /* 14px — body small, secondary */
--text-base: 1rem; /* 16px — body default */
--text-lg: 1.125rem; /* 18px — body large */
--text-xl: 1.25rem; /* 20px — subheadings */
--text-2xl: 1.5rem; /* 24px — section headings */
--text-3xl: 1.875rem; /* 30px — page headings */
--text-4xl: 2.25rem; /* 36px — hero / display */
--leading-tight: 1.25;
--leading-normal: 1.5;
--leading-relaxed: 1.75; /* preferred for body copy */
--leading-loose: 2;
}
Color tokens — semantic naming:
Tokens are named by purpose, not by shade. A module never references #1A3C6E directly — it uses --color-primary. When the brand color changes, one token change updates every module.
:root {
/* Brand */
--color-primary: #1A3C6E;
--color-primary-hover: #153060;
--color-primary-light: #EBF0F8;
/* Semantic */
--color-success: #2E7D32;
--color-success-light: #E8F5E9;
--color-warning: #E65100;
--color-warning-light: #FFF3E0;
--color-error: #C62828;
--color-error-light: #FFEBEE;
--color-info: #1565C0;
--color-info-light: #E3F2FD;
/* Neutrals */
--color-text-primary: #1A1A1A;
--color-text-secondary: #5A5A5A;
--color-text-disabled: #9A9A9A;
--color-border: #D4D4D4;
--color-surface: #FFFFFF;
--color-bg: #F5F5F5;
}
Other tokens:
:root {
/* Border radius */
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-full: 9999px; /* pills, avatars */
/* Shadows */
--shadow-sm: 0 1px 2px rgba(0,0,0,0.08);
--shadow-md: 0 4px 12px rgba(0,0,0,0.10);
--shadow-lg: 0 8px 24px rgba(0,0,0,0.12);
/* Motion */
--duration-fast: 120ms;
--duration-normal: 200ms;
--duration-slow: 350ms;
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
/* Touch targets */
--touch-target-min: 2.75rem; /* 44px — WCAG minimum */
/* Z-index scale */
--z-base: 0;
--z-dropdown: 100;
--z-sticky: 200;
--z-modal: 300;
--z-toast: 400;
}
Delivery: The token file is a standalone CSS file served from a CDN path and importable as an npm package. Every module — React, Vue, server-rendered .NET — imports this one file. No framework dependency.
Layer 2 — Component Library
The component library is a React package (@miqaat-core/design-system) published to the platform's private npm registry. All new greenfield modules building with React must use it. Modules do not build their own button, form field, table, or modal from scratch.
What ships in the library
Form elements
Input, Textarea, Select, Checkbox, Radio, Switch, DatePicker, FileUpload — all built on token values, all keyboard-navigable, all with built-in error and disabled states, all ARIA-labelled correctly.
Navigation and layout
TopNav, Sidebar, Breadcrumb, Tabs, PageShell — consistent across all modules so a Mumin navigating between modules feels no context switch.
Data display
Table (with sort, pagination, mobile collapse), Card, Badge, Tag, Avatar, Stat — used for registration lists, allocation summaries, HR dashboards, and scan reports.
Feedback and overlay
Button (primary, secondary, ghost, destructive), Alert, Toast, Modal, Drawer, Tooltip, Spinner, ProgressBar — consistent interaction patterns everywhere.
Lisan ud Daawat
<LisanText> — dedicated component for rendering Lisan ud Daawat content. Handles right-to-left direction, correct Unicode rendering, appropriate line height for the script, and prevents truncation artifacts. No module should attempt to render Lisan ud Daawat text outside this component.
How modules use it
npm install @miqaat-core/design-system
import { Button, Input, Table, LisanText } from '@miqaat-core/design-system'
import '@miqaat-core/design-system/tokens.css' // tokens always imported separately
function RegistrationForm() {
return (
<form>
<Input label="ITS ID" name="itsId" required />
<LisanText>محمد علي</LisanText>
<Button variant="primary" type="submit">Submit</Button>
</form>
)
}
Versioning and updates
The component library follows semantic versioning. Breaking changes (removed props, renamed components) require a major version bump and a minimum 8-week deprecation notice. Minor additions are backward-compatible. Modules are not required to be on the latest version, but must upgrade before the deprecation window closes on any version they depend on.
Layer 3 — Patterns and Guidelines
For module teams not on React — legacy .NET views, server-rendered HTML, Vue — Layer 3 provides:
Storybook reference — every component documented with visual examples, prop descriptions, and usage notes. Non-React teams use this as the visual spec for what they must replicate using the token system.
Pattern library — documented interaction patterns beyond individual components: how a multi-step form flows, how an empty state is handled, how errors surface at form level vs field level, how loading states work, how a confirmation dialog is structured.
Design review gate — before any module ships a new screen, the platform design team reviews against the guidelines. This is the only enforcement mechanism for non-React teams. It is a process gate, not a technical one — which means discipline from both sides is required.
Lisan ud Daawat — Special Handling
Lisan ud Daawat requires attention that generic component libraries do not provide:
Direction: dir="rtl" must be applied correctly at the text container level, not the page level (pages are mixed LTR/RTL in practice).
Font: A designated webfont that supports the full Dawoodi Bohra script is included in the token package. Modules do not load their own fonts for Lisan ud Daawat content.
Line height: The script requires a looser line height than Latin text at equivalent sizes. --leading-relaxed (1.75) is the minimum for body-level Lisan ud Daawat. Tighter values cause overlapping ascenders.
Truncation: Standard CSS text truncation (text-overflow: ellipsis) can break Lisan ud Daawat words in visually incorrect ways. The <LisanText> component handles truncation safely — or disables it where safe truncation is not possible.
Input fields: The Input component automatically switches to dir="rtl" when Lisan ud Daawat content is detected, and switches back when the field is cleared. This is built into the component — module teams do not implement this logic.
Accessibility Standards
The platform targets WCAG 2.1 Level AA as the minimum standard for all modules. The design system is the delivery mechanism — accessibility is built into every token and component, not retrofitted per module.
Color and contrast
All color token combinations used in the component library meet WCAG 1.4.3:
- Normal text on background: minimum contrast ratio 4.5:1
- Large text (≥ 1.5rem bold or ≥ 2rem regular) on background: minimum 3:1
- Interactive elements and UI components: minimum 3:1 against adjacent colors
Color is never the only way to convey information. Error states use both --color-error and an error icon. Required fields use both asterisk and aria-required. Status badges use both color and text label.
Keyboard navigation
Every interactive element in the component library is reachable and operable by keyboard alone:
- Tab order follows visual reading order
- Focus is never trapped (except inside open modals — intentional and ARIA-compliant)
- All actions achievable by mouse are achievable by keyboard
Escapecloses modals and dropdowns- Arrow keys navigate within menus, tabs, and select lists
Focus ring: A visible, high-contrast focus ring is shown on all focused elements. It is never suppressed for aesthetic reasons. The token --focus-ring (3px solid --color-primary with 2px offset) is applied globally.
Screen readers and ARIA
All components ship with correct ARIA roles, labels, and live regions:
- Form fields:
aria-labeloraria-labelledby,aria-required,aria-invalidwitharia-describedbypointing to the error message - Modals:
role="dialog",aria-modal="true",aria-labelledbypointing to the modal title, focus managed on open and restore on close - Live updates (toast notifications, status changes):
aria-live="polite"for non-urgent,aria-live="assertive"for critical alerts - Tables:
<caption>,scopeon headers,aria-sorton sortable columns - Loading states:
aria-busy="true"on the loading region,role="status"on spinners
Touch targets
All interactive elements meet WCAG 2.5.5 — minimum touch target size of 44×44px (2.75rem at base font size). The token --touch-target-min: 2.75rem is applied to all button and interactive element minimum heights. On mobile breakpoints, tap targets expand via padding if the visual element is smaller.
Motion and animation
The platform respects prefers-reduced-motion. All transitions and animations check this media query:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
This is set globally in the token stylesheet. Module teams do not need to implement it independently.
Zoom and reflow
Content must be readable and operable when zoomed to 400% without horizontal scrolling (WCAG 1.4.10 Reflow). The rem-based token system supports this naturally — text and layout scale with zoom. Fixed-pixel layouts break reflow. No module ships a layout with fixed-pixel widths for primary content areas.
Who Owns What
| Responsibility | Owner |
|---|---|
| Design token definitions | Core / Platform team |
| Component library (React) | Core / Platform team |
| Storybook and guidelines | Core / Platform team |
| Accessibility audit of the library | Core / Platform team |
| Module-level implementation | Each module team |
| Design review gate approval | Platform design team |
| Lisan ud Daawat font licensing | Core / Platform team |
| Requesting new components | Module teams — via request to Core |
| Deciding new component is built | Core team — based on cross-module need |
A module team that needs a component that does not exist in the library raises a request with the Core team. If the component is needed by more than one module, Core builds it into the library. If it is specific to one module, the module team builds it using the token system and follows the Layer 3 guidelines.
What Modules Must Do vs What is Optional
| Item | Mandatory | Optional |
|---|---|---|
| Import and use design tokens (CSS variables) | Yes — all modules | — |
| Use the React component library (if React) | Yes | — |
Use <LisanText> for all Lisan ud Daawat content | Yes | — |
| Pass design review gate before shipping | Yes | — |
| Meet WCAG 2.1 AA on all new screens | Yes | — |
| Use rem units for all spacing and typography | Yes | — |
| Contribute new components back to the library | No | Encouraged |
| Use platform fonts for Latin content | No | Recommended |
| Follow Storybook pattern docs for non-React stacks | Yes (process) | — |