Overview
What is MTS SaaS Admin Dashboard UI Kit?
A premium enterprise-ready SaaS Admin Dashboard UI Kit designed for modern web applications. It provides a complete, production-quality admin panel with 8 persona-specific dashboards, 100+ UI components, and support for light, dark, and high-contrast themes.
8 Dashboards
Persona-specific views for every role in your organization
100+ Components
Buttons, cards, tables, forms, modals, and more
3 Themes
Light, dark, and high-contrast modes
No Framework
Pure vanilla JS with ES Modules
Technology Foundation
Built with a carefully selected modern stack optimized for performance, maintainability, and developer experience:
- Vite 8 — Lightning-fast build tool with HMR
- Bootstrap 5.3 — CSS framework for grid, utilities, and components
- SCSS 1.103 — CSS preprocessing with design tokens
- Chart.js 4.5 — Interactive data visualizations
- Font Awesome 7.3 — Comprehensive icon library
- Vanilla JS ES Modules — No React, Vue, or Angular dependency
Tech Stack
A detailed breakdown of every technology in the stack, its version, and its role in the architecture.
| Technology | Version | Purpose |
|---|---|---|
| Vite | 8.2.2 | Build tool, dev server with HMR, asset bundling, multi-page app configuration |
| Bootstrap | 5.3 | CSS framework, responsive grid system, utility classes, base components |
| SCSS | 1.103.1 | CSS preprocessing, design tokens, mixins, theme system, variables |
| Chart.js | 4.5.1 | Interactive data visualizations (line, bar, doughnut, radar charts) |
| Font Awesome | 7.3.1 | Icon library with 2,000+ icons for UI elements and navigation |
| JavaScript | ES Modules | Vanilla JS, no framework — component functions returning HTML strings |
| Inter | Google Fonts | Primary sans-serif typeface for all UI text |
| JetBrains Mono | Google Fonts | Monospace typeface for code blocks and technical content |
Project Structure
The complete directory tree showing every file and folder in the project.
└── public/ # Static assets (FA CSS, webfonts, favicon)
└── src/
├── scss/ # 20 SCSS files
│ ├── app.scss # Main entry, imports all partials
│ ├── _variables.scss # Design tokens
│ ├── _mixins.scss # Reusable mixins (223 lines)
│ ├── _bootstrap.scss # Bootstrap 5 import
│ ├── _theme.scss # Theme base styles
│ ├── _theme-light.scss # Light theme CSS custom properties
│ ├── _theme-dark.scss # Dark + high-contrast themes
│ ├── _layout.scss # App shell, grids
│ ├── _sidebar.scss # Sidebar styles
│ ├── _header.scss # Header styles
│ ├── _cards.scss # KPI cards
│ ├── _badges.scss # Badges, avatars
│ ├── _skeleton.scss # Loading states
│ ├── _modals.scss # Toasts, modals
│ ├── _command-palette.scss
│ ├── _forms.scss # Form components
│ ├── _tables.scss # Table components
│ ├── _auth.scss # Auth page layouts
│ ├── _errors.scss # Error pages
│ └── _utilities.scss # Utility classes
├── js/ # 6 core modules
│ ├── app.js # Main entry (90 lines)
│ ├── config.js # APP_CONFIG object
│ ├── theme.js # Theme toggle/persistence (56 lines)
│ ├── sidebar.js # Sidebar behavior (79 lines)
│ ├── utils.js # Utility functions (103 lines)
│ └── demo-data.js # Mock data (97 lines)
├── components/ # 3 layout components
│ ├── layout.js # renderAppLayout, renderAuthLayout, renderErrorLayout
│ ├── sidebar-content.js # Sidebar navigation HTML
│ └── header-content.js # Header with search, profile, theme toggle
└── pages/ # 54 HTML pages + 54 JS modules
├── auth/ # 9 pages
├── dashboard/ # 10 pages (8 personas + index + user)
├── users/ # 4 pages (CRUD)
├── roles/ # 4 pages (CRUD)
├── customers/ # 2 pages
├── subscriptions/ # 3 pages
├── billing/ # 3 pages
├── reports/ # 3 pages
├── settings/ # 7 pages
├── notifications/ # 1 page
├── activity/ # 1 page
├── profile/ # 1 page
├── onboarding/ # 1 page
├── components/ # 1 page (showcase)
└── errors/ # 4 pages (401,403,404,500)
└── dist/ # Production build output
└── package.json
└── vite.config.js
└── README.md
SCSS Architecture
The stylesheet layer consists of 19 partials plus 1 main entry file, totaling 20 SCSS files. Bootstrap is imported via SCSS for full theme integration.
Import Chain
The import order is critical — each file depends on variables and mixins defined in earlier files:
// app.scss — Main entry point
@import 'variables'; // 1. Design tokens & SCSS variables
@import 'mixins'; // 2. Reusable mixins (223 lines)
@import 'bootstrap'; // 3. Bootstrap 5 full import
@import 'theme'; // 4. Theme base styles
@import 'theme-light'; // 5. Light theme custom properties
@import 'theme-dark'; // 6. Dark + high-contrast themes
@import 'layout'; // 7. App shell, grid system
@import 'sidebar'; // 8. Sidebar component
@import 'header'; // 9. Header component
@import 'cards'; // 10. KPI & stat cards
@import 'badges'; // 11. Badges & avatars
@import 'skeleton'; // 12. Skeleton loading states
@import 'modals'; // 13. Toasts & modals
@import 'command-palette';// 14. Command palette
@import 'forms'; // 15. Form components
@import 'tables'; // 16. Table components
@import 'auth'; // 17. Auth page layouts
@import 'errors'; // 18. Error page styles
@import 'utilities'; // 19. Custom utility classes
Key Design Decisions
@import 'bootstrap/scss/bootstrap' which provides full SCSS variable override capability. Font Awesome is loaded via <link> tag in HTML (not SCSS import) for proper bundling and caching.- All CSS custom properties are defined in theme files (
_theme-light.scss,_theme-dark.scss) - SCSS variables in
_variables.scssare compiled at build time; CSS custom properties enable runtime theming - Mixins in
_mixins.scssprovide reusable patterns for responsive design, focus states, text truncation, and more - Bootstrap utilities are extended, not replaced — custom utilities in
_utilities.scsssupplement Bootstrap's built-in set
Design Tokens
All design decisions are centralized in SCSS variables and CSS custom properties. These tokens ensure visual consistency across the entire application.
Color Palette
Brand Colors
| Variable | Value | Preview | Usage |
|---|---|---|---|
| $brand-orange | #E67E22 | Primary brand accent | |
| $brand-orange-light | #F39C12 | Hover states, highlights | |
| $brand-orange-dark | #D35400 | Active states, emphasis | |
| $brand-charcoal | #2C3E50 | Sidebar, dark surfaces | |
| $brand-dark | #1a1d23 | Deepest dark backgrounds |
Blue Scale
| Variable | Value | Preview |
|---|---|---|
| $blue-50 | #EFF6FF | |
| $blue-100 | #DBEAFE | |
| $blue-200 | #BFDBFE | |
| $blue-300 | #93C5FD | |
| $blue-400 | #60A5FA | |
| $blue-500 | #3B82F6 | |
| $blue-600 | #2563EB | |
| $blue-700 | #1D4ED8 |
Green Scale
| Variable | Value | Preview |
|---|---|---|
| $green-50 | #F0FDF4 | |
| $green-100 | #DCFCE7 | |
| $green-200 | #BBF7D0 | |
| $green-300 | #86EFAC | |
| $green-400 | #4ADE80 | |
| $green-500 | #22C55E | |
| $green-600 | #16A34A | |
| $green-700 | #15803D |
Red Scale
| Variable | Value | Preview |
|---|---|---|
| $red-50 | #FEF2F2 | |
| $red-100 | #FEE2E2 | |
| $red-200 | #FECACA | |
| $red-300 | #FCA5A5 | |
| $red-400 | #F87171 | |
| $red-500 | #EF4444 | |
| $red-600 | #DC2626 | |
| $red-700 | #B91C1C |
Yellow, Purple, Teal Scales
| Variable | Value | Preview |
|---|---|---|
| $yellow-50 | #FEFCE8 | |
| $yellow-300 | #FDE047 | |
| $yellow-500 | #EAB308 | |
| $yellow-600 | #CA8A04 | |
| $purple-50 | #FAF5FF | |
| $purple-300 | #D8B4FE | |
| $purple-500 | #A855F7 | |
| $purple-600 | #9333EA | |
| $teal-50 | #F0FDFA | |
| $teal-300 | #5EEAD4 | |
| $teal-500 | #14B8A6 | |
| $teal-600 | #0D9488 |
Gray Scale
| Variable | Value | Preview |
|---|---|---|
| $gray-25 | #FCFCFD | |
| $gray-50 | #F9FAFB | |
| $gray-100 | #F2F4F7 | |
| $gray-200 | #EAECF0 | |
| $gray-300 | #D0D5DD | |
| $gray-400 | #98A2B3 | |
| $gray-500 | #667085 | |
| $gray-600 | #475467 | |
| $gray-700 | #344054 | |
| $gray-800 | #1D2939 | |
| $gray-900 | #101828 |
Spacing Scale
Based on a 4px base unit, providing consistent spatial rhythm throughout the UI.
| Variable | Value | Pixels |
|---|---|---|
| $space-0 | 0 | 0px |
| $space-0.5 | 0.125rem | 2px |
| $space-1 | 0.25rem | 4px |
| $space-1.5 | 0.375rem | 6px |
| $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 |
| $space-20 | 5rem | 80px |
Typography
| Category | Token | Value |
|---|---|---|
| Font Families | $font-family-sans | 'Inter', system-ui, -apple-system, sans-serif |
| $font-family-mono | 'JetBrains Mono', 'Fira Code', monospace | |
| Font Sizes | $font-size-xs | 12px (0.75rem) |
| $font-size-sm | 13px (0.8125rem) | |
| $font-size-base | 14px (0.875rem) | |
| $font-size-md | 16px (1rem) | |
| $font-size-lg | 18px (1.125rem) | |
| $font-size-xl | 20px (1.25rem) | |
| Extended Sizes | $font-size-2xl | 24px (1.5rem) |
| $font-size-3xl / 4xl | 30px / 36px | |
| Font Weights | $font-weight-regular | 400 |
| $font-weight-medium | 500 | |
| $font-weight-semibold | 600 | |
| $font-weight-bold | 700 | |
| Line Heights | $line-height-tight | 1.25 |
| $line-height-snug | 1.375 | |
| $line-height-normal | 1.5 | |
| $line-height-relaxed | 1.625 |
Border Radius
| Variable | Value | Usage |
|---|---|---|
| $radius-none | 0 | No rounding |
| $radius-sm | 4px | Buttons, inputs |
| $radius-md | 6px | Cards, dropdowns |
| $radius-lg | 8px | Modals, panels |
| $radius-xl | 12px | Large cards, containers |
| $radius-2xl | 16px | Feature cards |
| $radius-full | 9999px | Pill shape, avatars |
Shadows
| Variable | CSS Value |
|---|---|
| $shadow-xs | 0 1px 2px rgba(0,0,0,.05) |
| $shadow-sm | 0 1px 3px rgba(0,0,0,.1), 0 1px 2px rgba(0,0,0,.06) |
| $shadow-md | 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.06) |
| $shadow-lg | 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px rgba(0,0,0,.05) |
| $shadow-xl | 0 20px 25px -5px rgba(0,0,0,.1), 0 10px 10px rgba(0,0,0,.04) |
Z-Index Scale
| Variable | Value | Usage |
|---|---|---|
| $z-dropdown | 1000 | Dropdown menus |
| $z-sticky | 1020 | Sticky headers |
| $z-fixed | 1030 | Fixed sidebar |
| $z-modal-backdrop | 1040 | Modal overlays |
| $z-modal | 1050 | Modal dialogs |
| $z-popover | 1060 | Popovers |
| $z-tooltip | 1070 | Tooltips |
| $z-toast | 1080 | Toast notifications |
| $z-command | 1090 | Command palette |
Transitions
| Variable | Value | Usage |
|---|---|---|
| $transition-fast | 150ms ease | Hover states, focus rings |
| $transition-base | 200ms ease | General transitions |
| $transition-slow | 300ms ease | Panel slides, modals |
| $transition-spring | 300ms cubic-bezier(.34,1.56,.64,1) | Bouncy, playful animations |
Breakpoints
| Variable | Value | Description |
|---|---|---|
| $bp-xs | 0 | Default (mobile first) |
| $bp-sm | 576px | Small devices (landscape phones) |
| $bp-md | 768px | Medium devices (tablets) |
| $bp-lg | 992px | Large devices (desktops) |
| $bp-xl | 1200px | Extra large devices (large desktops) |
| $bp-2xl | 1400px | XXL devices (wide screens) |
Layout Dimensions
| Variable | Value | Description |
|---|---|---|
| $sidebar-width | 260px | Full sidebar width |
| $sidebar-collapsed | 72px | Collapsed sidebar width |
| $sidebar-mobile-width | 280px | Mobile drawer sidebar |
| $header-height | 64px | Fixed header height |
Theme System
The theme system supports three themes: light, dark, and high-contrast. Themes are implemented using CSS custom properties on the <html> element via the data-theme attribute.
Theme Architecture
Light Theme
Default theme with white surfaces and dark text. Optimized for bright environments.
Dark Theme
Dark surfaces with light text. Reduces eye strain in low-light conditions.
High Contrast
Maximum contrast ratio for vision accessibility. WCAG AAA compliance.
How It Works
// Setting the theme
document.documentElement.setAttribute('data-theme', 'dark');
// Persisting the choice
localStorage.setItem('mts-theme', 'dark');
// Detecting system preference
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
CSS Custom Properties (Light Theme)
| Property | Value | Usage |
|---|---|---|
| --mts-primary | #E67E22 | Primary brand color |
| --mts-primary-hover | #D35400 | Primary hover state |
| --mts-primary-light | #F39C12 | Light primary variant |
| --mts-primary-rgb | 230, 126, 34 | Primary as RGB (for rgba) |
| --mts-primary-bg | rgba(230,126,34,.08) | Primary background tint |
| --mts-success | #27AE60 | Success semantic color |
| --mts-success-bg | #EAFAF1 | Success background |
| --mts-success-border | #A9DFBF | Success border |
| --mts-warning | #F39C12 | Warning semantic color |
| --mts-warning-bg | #FEF9E7 | Warning background |
| --mts-warning-border | #F9E79F | Warning border |
| --mts-danger | #E74C3C | Danger semantic color |
| --mts-danger-bg | #FDEDEC | Danger background |
| --mts-danger-border | #F5B7B1 | Danger border |
| --mts-info | #3498DB | Info semantic color |
| --mts-info-bg | #EBF5FB | Info background |
| --mts-info-border | #AED6F1 | Info border |
| Property | Value | Usage |
|---|---|---|
| --mts-background | #F8F9FA | Page background |
| --mts-surface | #FFFFFF | Surface background |
| --mts-card | #FFFFFF | Card background |
| --mts-card-hover | #F8F9FA | Card hover state |
| --mts-border | #E9ECEF | Default border color |
| --mts-border-light | #F1F3F5 | Light border |
| --mts-divider | #E9ECEF | Divider lines |
| --mts-hover | rgba(0,0,0,.04) | Row hover tint |
| --mts-active | rgba(0,0,0,.06) | Active/selected state |
| --mts-text-primary | #1a1d23 | Primary text |
| --mts-text-secondary | #6C757D | Secondary text |
| --mts-text-muted | #ADB5BD | Muted text |
| --mts-text-inverse | #FFFFFF | Inverse text (on dark) |
| --mts-text-link | #E67E22 | Link text color |
| --mts-sidebar-bg | #2C3E50 | Sidebar background |
| --mts-sidebar-text | #BDC3C7 | Sidebar text |
| --mts-sidebar-text-hover | #ECF0F1 | Sidebar hover text |
| --mts-sidebar-text-active | #E67E22 | Sidebar active text |
| --mts-sidebar-active-bg | rgba(230,126,34,.08) | Sidebar active background |
| --mts-sidebar-hover-bg | rgba(255,255,255,.08) | Sidebar hover background |
| --mts-sidebar-border | rgba(255,255,255,.06) | Sidebar border |
| --mts-sidebar-width | 260px | Sidebar width |
| --mts-sidebar-collapsed-width | 72px | Collapsed sidebar width |
| --mts-header-bg | #FFFFFF | Header background |
| --mts-header-border | #E9ECEF | Header border |
| --mts-header-height | 64px | Header height |
| --mts-input-bg | #FFFFFF | Input background |
| --mts-input-border | #D0D5DD | Input border |
| --mts-input-focus-border | #E67E22 | Input focus border |
| --mts-input-focus-shadow | 0 0 0 3px rgba(230,126,34,.15) | Input focus ring |
| --mts-input-placeholder | #98A2B3 | Input placeholder text |
| --mts-skeleton-base | #E9ECEF | Skeleton base color |
| --mts-skeleton-shine | #F8F9FA | Skeleton shimmer |
| --mts-overlay-bg | rgba(0,0,0,.5) | Overlay background |
| --mts-modal-bg | #FFFFFF | Modal background |
| --mts-dropdown-bg | #FFFFFF | Dropdown background |
| --mts-toast-bg | #FFFFFF | Toast background |
| --mts-shadow-xs | 0 1px 2px rgba(0,0,0,.05) | Extra small shadow |
| --mts-shadow-sm | 0 1px 3px rgba(0,0,0,.1) | Small shadow |
| --mts-shadow-md | 0 4px 6px rgba(0,0,0,.1) | Medium shadow |
| --mts-shadow-lg | 0 10px 15px rgba(0,0,0,.1) | Large shadow |
| --mts-shadow-xl | 0 20px 25px rgba(0,0,0,.1) | Extra large shadow |
| --mts-chart-1 | #E67E22 | Chart series 1 |
| --mts-chart-2 | #3498DB | Chart series 2 |
| --mts-chart-3 | #27AE60 | Chart series 3 |
| --mts-chart-4 | #E74C3C | Chart series 4 |
| --mts-chart-5 | #9B59B6 | Chart series 5 |
| --mts-chart-6 | #1ABC9C | Chart series 6 |
| --mts-chart-grid | #E9ECEF | Chart grid lines |
| --mts-chart-text | #6C757D | Chart labels/legend |
Theme Storage & Switching
- Storage key:
localStoragekeymts-theme - Attribute:
data-themeon<html>element - System detection:
matchMedia('(prefers-color-scheme: dark)') - Default: Falls back to system preference if no stored choice
Mixins Reference
All 18 mixins defined in _mixins.scss (223 lines). These provide reusable patterns that reduce code duplication.
| Mixin | Signature | Description |
|---|---|---|
respond-above | @include respond-above() | Applies styles above a breakpoint using min-width media query. |
respond-below | @include respond-below() | Applies styles below a breakpoint using max-width media query. |
respond-between | @include respond-between(, ) | Applies styles between two breakpoints. |
focus-ring | @include focus-ring(, ) | Visible focus ring for keyboard navigation. Default: orange, 2px offset. |
focus-ring-inset | @include focus-ring-inset() | Inset focus ring for elements where ring appears inside the border. |
text-truncate | @include text-truncate | Single-line truncation with ellipsis. |
text-clamp | @include text-clamp() | Multi-line truncation using -webkit-line-clamp. |
custom-scrollbar | @include custom-scrollbar(, , ) | Custom scrollbar styling for WebKit and Firefox. |
absolute-fill | @include absolute-fill | Absolute positioning covering nearest positioned parent. |
fixed-fill | @include fixed-fill | Fixed positioning covering full viewport. |
flex-center | @include flex-center | Flexbox centering: align-items + justify-content center. |
flex-between | @include flex-between | Flexbox space-between layout. |
flex-col-center | @include flex-col-center | Vertical flexbox centering with column direction. |
card-surface | @include card-surface | Standard card: background, border, radius, padding. |
elevated-surface | @include elevated-surface | Elevated card with shadow for floating elements. |
interactive-row | @include interactive-row | Table row with hover, pointer cursor, and transition. |
sr-only | @include sr-only | Screen reader only: visually hidden but accessible. |
skeleton-loading | @include skeleton-loading | Animated skeleton placeholder with shimmer keyframes. |
reduced-motion | @include reduced-motion | Disables animations for users who prefer reduced motion. |
JavaScript Architecture
The JavaScript layer uses vanilla ES Modules with no framework. Each page has its own module that imports shared components and utilities.
APP_CONFIG
Central configuration object exported from config.js:
export const APP_CONFIG = {
name: 'MTS SaaS Admin Dashboard',
version: '1.0.0',
company: 'MageTech Solutions',
apiBaseUrl: 'https://api.mts-saas.dev/v1',
environment: 'development',
currency: 'INR',
currencySymbol: '\u20B9',
locale: 'en-IN',
dateFormat: 'DD MMM YYYY',
timeFormat: 'hh:mm A',
defaultAvatar: '/assets/default-avatar.png',
logo: '/assets/logo.svg',
logoSmall: '/assets/logo-small.svg',
favicon: '/favicon.ico',
sidebarWidth: 260,
sidebarCollapsedWidth: 72,
headerHeight: 64,
pageSize: 10,
toastDuration: 4000,
commandPaletteKey: 'k'
};
Core Modules
| Module | Lines | Exports | Purpose |
|---|---|---|---|
app.js | 90 | initApp | Main entry point. Initializes theme, sidebar, search, command palette, quick actions. |
config.js | 35 | APP_CONFIG | Central configuration object with app-wide settings. |
theme.js | 56 | getTheme, setTheme, toggleTheme, initTheme, getSystemTheme, updateThemeIcon | Theme management: toggle, persist, detect system preference. |
sidebar.js | 79 | initSidebar, initNavToggles, setActiveNav | Sidebar behavior: expand/collapse, mobile drawer, active state. |
utils.js | 103 | 13 functions (see below) | Shared utility functions for formatting, DOM, and UX helpers. |
demo-data.js | 97 | 10 data exports | Mock data for development and demos. |
Utility Functions (utils.js)
| Function | Signature | Returns | Description |
|---|---|---|---|
formatCurrency | formatCurrency(amount) | string | Formats number as INR currency (e.g. \u20B91,23,456.00) |
formatNumber | formatNumber(num) | string | Formats number with locale-specific thousand separators |
formatDate | formatDate(date) | string | Formats date using app dateFormat (DD MMM YYYY) |
formatDateTime | formatDateTime(date) | string | Formats date + time (DD MMM YYYY, hh:mm A) |
debounce | debounce(fn, delay) | function | Delays function execution until after delay ms of inactivity |
getInitials | getInitials(name) | string | Extracts initials from full name (max 2 chars) |
generateId | generateId() | string | Generates unique ID using crypto.randomUUID() |
slugify | slugify(text) | string | Converts text to URL-friendly slug |
truncate | truncate(text, length) | string | Truncates text to length with ellipsis |
escapeHtml | escapeHtml(str) | string | Escapes HTML special characters to prevent XSS |
copyToClipboard | copyToClipboard(text) | Promise | Copies text to clipboard with fallback |
showToast | showToast(message, type) | void | Displays toast notification (success/error/warning/info) |
showModal | showModal(title, content) | void | Opens modal dialog with title and HTML content |
ES Module Pattern
Each page follows a consistent import/export pattern:
// src/pages/dashboard/saas-owner.js
import { renderAppLayout } from '../../components/layout.js';
import { renderSidebar } from '../../components/sidebar-content.js';
import { renderHeader } from '../../components/header-content.js';
import { formatCurrency } from '../../js/utils.js';
import { COMPANIES, REVENUE_DATA } from '../../js/demo-data.js';
function renderContent() {
return <div class='dashboard'>...</div>;
}
const app = document.getElementById('app');
app.innerHTML = renderAppLayout(renderContent(), {
pageTitle: 'SaaS Owner Dashboard',
activePage: 'saas-owner'
});
Component System
The component system is built around three layout components and a library of reusable UI patterns.
Layout Components (layout.js)
| Function | Parameters | Description |
|---|---|---|
renderAppLayout | (content, options) | Main dashboard layout with sidebar + header + content. Options: { pageTitle, breadcrumbs, activePage } |
renderAuthLayout | (content, options) | Auth page with split/centered layout. Options: { split, brandTitle, brandDescription } |
renderErrorLayout | (code, title, message) | Error page template for 401, 403, 404, 500. |
Sidebar (sidebar-content.js)
renderSidebar(activePage) generates complete sidebar HTML with logo, workspace switcher, and 7 navigation sections:
- Dashboard — 8 persona dashboards + general + user
- Analytics — Reports, revenue, customer analytics
- Management — Users, roles, customers, activity
- Subscription — Plans, subscription management
- Finance — Billing, invoices, payment methods
- Support — Tickets, notifications
- Configuration — Settings (7 tabs), profile, onboarding
Header (header-content.js)
renderHeader(pageTitle, breadcrumbs) generates:
- Sidebar toggle button (collapse/expand)
- Breadcrumb navigation trail
- Global search bar with Cmd+K shortcut
- Notification bell with unread badge
- Theme toggle (light/dark/high-contrast)
- Profile dropdown with user avatar and actions
UI Component Showcase
Buttons
Primary, secondary, outline, ghost, danger + all sizes (sm, md, lg)
Cards
KPI, stat, content, feature card variants
Tables
Sortable, striped, hover, responsive data tables
Forms
Inputs, selects, textareas, toggles, checkboxes, radios
Badges
Status, role, and count badge variants
Modals
Confirm, form, and info modal dialogs
Alerts
Success, warning, danger, info alert banners
More
Dropdowns, tabs, accordions, tooltips, skeletons, avatar groups
Page Architecture
Each page follows a consistent pattern with its own HTML entry point and JS module.
Page Pattern
Every HTML page contains a minimal shell:
<div id="app"></div>
<script type="module" src="/src/pages/[module]/[page].js"></script>
The JS module then:
- Imports
renderAppLayoutfrom layout.js - Imports
renderSidebarfrom sidebar-content.js - Imports
renderHeaderfrom header-content.js - Builds page-specific content as an HTML string
- Calls
renderAppLayout(contentHTML, { pageTitle, activePage }) - Sets
document.getElementById("app").innerHTMLto the result
Dashboard Personas
| Persona | Focus | Key Metrics |
|---|---|---|
| SaaS Owner | Business overview | MRR, ARR, growth rate, revenue charts, customer growth, churn rate |
| Super Admin | System health | User activity, system metrics, admin actions, audit logs |
| Org Admin | Organization | Team members, org settings, permissions, departments |
| Manager | Team performance | Team productivity, task completion, KPIs, attendance |
| Finance | Revenue | Invoices, payments, revenue breakdown, cash flow |
| Support | Customer service | Ticket queue, response times, satisfaction scores, SLA |
| Sales | Revenue pipeline | Deals, conversion rates, pipeline value, targets |
| User | Personal | Usage stats, subscription status, activity timeline |
Auth Pages (9 total)
| Page | Purpose |
|---|---|
login | Email/password login with remember me |
register | New account registration |
forgot-password | Password reset request |
reset-password | Set new password via token |
verify-email | Email verification confirmation |
otp | One-time password verification |
two-factor | Two-factor authentication setup/verify |
account-locked | Account lockout notice |
session-expired | Session timeout notice |
CRUD Pages
Users Module (4 pages)
- index — User list with search, role filter, status filter, pagination
- create — New user form with role assignment and department selection
- edit — Edit existing user details, role, and permissions
- view — User profile with activity timeline and session history
Roles Module (4 pages)
- index — Role list with permission count and user count
- create — Role creation with full RBAC permission matrix
- edit — Edit role permissions and description
- view — Role details with assigned users list
Feature Pages
Customers
- index — Customer list with filters (plan, status, industry, MRR range)
- view — Detailed customer profile with activity, billing, and usage data
Subscriptions
- index — Subscription overview with MRR and subscriber counts
- plans — Pricing tier management (Free, Starter, Pro, Enterprise, Custom)
- view — Individual subscription detail with billing history
Billing
- index — Billing overview with revenue summary
- invoices — Invoice list with status, amount, download
- payment-methods — Manage saved cards and payment methods
Reports
- index — Report dashboard with chart previews
- revenue — Revenue analytics with Chart.js visualizations
- customers — Customer analytics (acquisition, retention, LTV)
Settings (7 Tabs)
| Tab | Configuration Options |
|---|---|
| General | Company name, logo, timezone, language, date format |
| Appearance | Theme selection, accent color, sidebar behavior, font size |
| Security | Password policy, 2FA, session timeout, IP whitelist |
| Notifications | Email alerts, push notifications, digest frequency |
| Billing | Plan details, payment history, update payment method |
| Team | Team members, invite users, role assignments |
| Integrations | API keys, webhooks, third-party service connections |
Other Feature Pages
- notifications — Notification center with read/unread states and categories
- activity — Audit log with user, action, module, timestamp, IP, device filters
- profile — User profile with avatar, personal details, security, activity
- onboarding — Multi-step wizard for new user setup
- components — Full UI component showcase page
Error Pages
| Code | Title | When Shown |
|---|---|---|
| 401 | Unauthorized | User not authenticated or token expired |
| 403 | Forbidden | Authenticated but insufficient permissions |
| 404 | Not Found | Page or resource does not exist |
| 500 | Server Error | Internal server or application error |
Build System
Powered by Vite 8.2.2 with multi-page app configuration for optimized builds.
Vite Configuration
// vite.config.js
import { defineConfig } from 'vite';
import { resolve } from 'path';
export default defineConfig({root: '.',publicDir: 'public',
css: { preprocessorOptions: { scss: { api: 'legacy',
silenceDeprecations: ['legacy-js-api'] } } },
build: { outDir: 'dist', emptyOutDir: true },
resolve: { alias: { '@': resolve(__dirname, 'src'),
'@scss': resolve(__dirname, 'src/scss'),
'@js': resolve(__dirname, 'src/js'),
'@components': resolve(__dirname, 'src/components'),
'@pages': resolve(__dirname, 'src/pages') } },
rollupOptions: { input: {
// 53+ entry points for multi-page build
'main': resolve(__dirname, 'index.html'),
'login': resolve(__dirname, 'src/pages/auth/login.html'),
// ... additional entry points for all 54 pages
} } }
});
Build Output
dist/
All HTML, JS, CSS, and static assets
Code Split
JS bundles per page for optimal loading
CSS Extraction
theme-[hash].css with all styles
Cache Busting
Hash-suffixed assets for long-term caching
Commands
| Command | Description |
|---|---|
npm run dev | Start Vite dev server with hot module replacement (HMR) |
npm run build | Production build with optimized assets and code splitting |
npm run preview | Preview the production build locally before deployment |
Data Layer
All mock data is centralized in demo-data.js for development and demos. No backend required.
| Export | Records | Key Fields |
|---|---|---|
COMPANIES | 12 | id, name, domain, industry, employees, plan, mrr, since, status |
USERS | 8 | id, name, email, role, department, status, lastLogin, created |
PLANS | 5 | id, name, price, period, features[], color |
INVOICES | 8 | id, customer, amount, date, due, status, method |
REVENUE_DATA | 8 months | labels, mrr, arr, revenue arrays |
CUSTOMER_GROWTH | 8 months | labels, new, churned, total arrays |
ACTIVITY_LOG | 8 entries | user, action, module, ip, device, time, status |
NOTIFICATIONS | 8 entries | id, title, message, category, read, time |
SUPPORT_TICKETS | 5 | id, subject, customer, priority, status, agent, created |
SALES_PIPEELINE | 5 | id, deal, value, stage, rep, probability, expectedClose |
Accessibility
Built with WCAG 2.2 AA compliance as a core requirement, not an afterthought.
Keyboard Navigation
Full keyboard support with logical tab order and visible focus indicators via focus-ring mixin
ARIA Labels
All interactive elements have proper ARIA labels and roles for screen reader compatibility
Screen Reader
sr-only class for visually hidden but accessible content; semantic HTML throughout
Reduced Motion
reduced-motion mixin respects prefers-reduced-motion system setting
High Contrast
Dedicated high-contrast theme for vision accessibility (WCAG AAA)
Color Contrast
All text and interactive elements meet AA contrast ratios against their backgrounds
Implementation Details
- Focus management:
focus-ring()mixin provides 2px offset orange ring on :focus-visible - Skip links: Hidden skip-to-content link at top of page for keyboard users
- Form labels: All form inputs have associated labels (visible or sr-only)
- Error identification: Form errors use aria-describedby and aria-invalid
- Live regions: Toast notifications use aria-live="polite" for dynamic updates
- Landmark roles: Semantic nav, main, header, footer elements throughout
Browser Support
Tested and supported on the latest 2 versions of all major browsers.
| Browser | Versions | Engine |
|---|---|---|
| Google Chrome | Latest 2 | Blink |
| Microsoft Edge | Latest 2 | Blink |
| Mozilla Firefox | Latest 2 | Gecko |
| Apple Safari | Latest 2 | WebKit |
API Reference
Complete reference for all exported functions and their usage.
Layout API (layout.js)
| Function | Parameters | Returns |
|---|---|---|
renderAppLayout | content: string, options: { pageTitle, breadcrumbs?, activePage } | string (full page HTML) |
renderAuthLayout | content: string, options: { split?, brandTitle?, brandDescription? } | string |
renderErrorLayout | code: number, title: string, message: string | string |
Theme API (theme.js)
| Function | Parameters | Returns |
|---|---|---|
getTheme | () | string - current theme name |
setTheme | theme: string | void |
toggleTheme | () | void - cycles light/dark/high-contrast |
initTheme | () | void - reads stored or system preference |
getSystemTheme | () | string - detects OS preference |
updateThemeIcon | theme: string | void - updates toggle button icon |
Sidebar API (sidebar.js)
| Function | Parameters | Returns |
|---|---|---|
initSidebar | () | void - initializes sidebar behavior |
initNavToggles | () | void - sets up expand/collapse toggles |
setActiveNav | pageId: string | void - highlights active nav link |
Deployment Guide
A pure client-side application with no server-side dependencies. Deploy anywhere that serves static files.
Static Hosting Options
Netlify / Vercel
Drag-and-drop dist/ folder or connect Git repository for auto-deploy
Apache / Nginx
Copy dist/ to web root and configure URL rewriting for SPA routing
XAMPP / WAMP
Copy to htdocs directory, access via localhost/mtssasadmindashboarduikit
AWS S3 / CloudFront
Upload dist/ to S3 bucket with CloudFront CDN distribution
Deployment Steps
- Run
npm run buildto generate the dist/ folder - Upload the contents of dist/ to your hosting provider
- Configure your server to serve index.html for all routes (SPA fallback)
- Enable gzip/brotli compression for optimal performance
- Set cache headers for hashed assets (1 year) and HTML files (no-cache)
Configuration
Customize branding by editing APP_CONFIG in src/js/config.js:
// src/js/config.js
export const APP_CONFIG = {
name: 'Your App Name',
company: 'Your Company',
logo: '/assets/your-logo.svg',
apiBaseUrl: 'https://your-api.com/v1',
currency: 'USD',
currencySymbol: '$',
};
npm run dev and all changes are reflected instantly via HMR. The production build only needs to be run before deployment.