A zero-dependency UI toolkit built from scratch. Vanilla JavaScript modules and an SCSS-based styling system — no external libraries.
I wrote this for my own project. If you're curious about building a UI toolkit from scratch with vanilla JS, keeping consistency across modules, or organizing SCSS architecture, this might give you some ideas.
Maintained on best-effort basis. Issues welcome but not guaranteed to be addressed.
npm run dev # Dev server (hot reload)
npm run build # Production build
npm run release # Build + update GitHub Pages docs
npm test # Run testsBuild output goes to dist/: sadrazam.esm.js and sadrazam.min.css.
npm install sadrazam// Full library
import Sadrazam from 'sadrazam';
// Cherry-pick — only the modules you need end up in your bundle
import Modal from 'sadrazam/js/modules/modal';
import Tooltip from 'sadrazam/js/modules/tooltip';
import Ajax from 'sadrazam/js/services/ajax';unpkg
<link rel="stylesheet" href="https://unpkg.com/sadrazam/dist/sadrazam.min.css">
<script type="module">
import Sadrazam from 'https://unpkg.com/sadrazam/dist/sadrazam.esm.js';
Sadrazam.configure({
languageCode: 'tr',
logEndpoint: '/api/log/js-error',
tokenSelector: "input[name='_token']"
});
</script>jsDelivr (npm)
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sadrazam/dist/sadrazam.min.css">
<script type="module">
import Sadrazam from 'https://cdn.jsdelivr.net/npm/sadrazam/dist/sadrazam.esm.js';
Sadrazam.configure({
languageCode: 'tr',
logEndpoint: '/api/log/js-error',
tokenSelector: "input[name='_token']"
});
</script>jsDelivr (GitHub — works without npm publish)
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/edukah/sadrazam/dist/sadrazam.min.css">
<script type="module">
import Sadrazam from 'https://cdn.jsdelivr.net/gh/edukah/sadrazam/dist/sadrazam.esm.js';
Sadrazam.configure({
languageCode: 'tr',
logEndpoint: '/api/log/js-error',
tokenSelector: "input[name='_token']"
});
</script>// All styles
@use 'pkg:sadrazam';
// Cherry-pick
@use 'sadrazam/scss/modules/modal';
@use 'sadrazam/scss/modules/tabs';The
pkg:protocol requires Dart Sass 1.71+ andNodePackageImporter. In webpack, add it to your sass-loader options:// webpack.config.js { loader: 'sass-loader', options: { sassOptions: { importers: [new require('sass').NodePackageImporter()] } } }
Type Sadrazam.help() in the console to see all available modules.
src/
├── js/
│ ├── core/ # Event system, polyfills
│ ├── helpers/ # DOM, form, cookie, URL utilities
│ ├── language/ # i18n system (tr, en)
│ ├── modules/ # UI components
│ ├── services/ # Ajax, LogRelay
│ └── index.js # Entry point
│
└── scss/
├── theme/ # Color definitions
├── base/ # Variables, fonts, typography, reset
├── components/ # Form elements, buttons, links
├── layout/ # Grid system, box model
├── modules/ # UI component styles (mirrors JS modules)
├── utilities/ # Helper classes
└── main.scss # SCSS entry point
| Module | Description |
|---|---|
Ajax |
Promise-based HTTP request manager |
LogRelay |
Global JS error capture and relay to backend |
Language |
Static i18n manager |
| Module | SCSS | Description |
|---|---|---|
Modal |
✓ | Modal window manager |
Toast |
✓ | Modal-based toast notifications |
Snackbar |
✓ | Toast notifications (singleton) |
SnackbarRelay |
— | Cross-page snackbar relay via sessionStorage |
Spinner |
✓ | Loading indicator (reference counting) |
Tabs |
✓ | Tab navigation (4 variants) |
Tooltip |
✓ | Tooltip |
Popover |
✓ | Popover |
Hovermenu |
✓ | Dropdown menu |
SlideMenu |
✓ | Sliding side panel |
Backdrop |
✓ | Backdrop overlay |
Autocomplete |
✓ | Autocomplete input |
ProgressBar |
✓ | Progress bar indicator |
InfiniteScroll |
— | Infinite scroll |
| Module | Description |
|---|---|
Form |
Rule-based form validation (data-form-validate) |
AutosizeTextarea |
Auto-height based on content |
AutosizeSelect |
Auto-width based on content |
| Module | Description |
|---|---|
Elem |
DOM element helpers |
Document |
Redirect, clipboard, UUID |
InsertScript |
Execute scripts inside AJAX-loaded HTML |
Url |
URL parameter management |
Token |
CSRF token management |
Cookie |
Cookie CRUD |
Event |
addEventListener wrapper |
ScrollHistory |
Scroll position memory |
Browser |
Browser detection |
Device |
Device detection |
Viewport |
Viewport helpers |
6-layer import order:
1. THEME → Color definitions (primary, secondary, tertiary, grey, semantic)
2. BASE → Variables, fonts, normalize, reset, typography
3. LAYOUT → Grid, box model
4. COMPONENTS → Form elements, buttons, links
5. MODULES → UI component styles
6. UTILITIES → Helper classes
All values are defined as CSS custom properties. Utility classes reference them via var(), making runtime theme switching possible.
A few things that might be interesting if you dig into the source:
- Zero dependencies — How to build modal, tooltip, autocomplete, toast from scratch in vanilla JS
- Reference counting — Managing nested async calls in Spinner (
show/hidewith internal reference counting) - Singleton pattern — Queue management with a single instance in Snackbar (toast)
- Barrel file pattern — SCSS
_form.scssas a barrel aggregating button, switch, form-patterns - CSS custom property architecture — Definition and utility class in the same file, 1:1 mapping
- JS ↔ SCSS module mirroring — Every JS UI component has a matching SCSS file with the same name
- LogRelay — Global
window.onerror+unhandledrejectioncapture with backend relay and deduplication
Some modules (Modal, Popover, Autocomplete, Snackbar, Toast) accept HTML content via innerHTML. Sadrazam does not sanitize this input — it is your responsibility to ensure all content passed to these modules is trusted.
Webpack 5, Babel 7, Dart Sass 1.86+, ESLint 9.
MIT